import logging.config from aiogram import F, Router 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.states.states import AddBybitApiState from logger_helper.logger_helper import LOGGING_CONFIG logging.config.dictConfig(LOGGING_CONFIG) logger = logging.getLogger("add_bybit_api") router_add_bybit_api = Router(name="add_bybit_api") @router_add_bybit_api.callback_query(F.data == "connect_platform") async def connect_platform(callback: CallbackQuery, state: FSMContext) -> None: """ Handles the callback query to initiate Bybit platform connection. Sends instructions on how to create and provide API keys to the bot. :param callback: CallbackQuery object triggered by user interaction. :param state: FSMContext object to manage state data. :return: None """ try: await state.clear() await callback.answer() user = await rq.get_user(tg_id=callback.from_user.id) if user: await callback.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=callback.from_user.id, username=callback.from_user.username ) await rq.set_user_symbol(tg_id=callback.from_user.id, symbol="BTCUSDT") await rq.create_user_additional_settings(tg_id=callback.from_user.id) await rq.create_user_risk_management(tg_id=callback.from_user.id) await rq.create_user_conditional_settings(tg_id=callback.from_user.id) await connect_platform(callback=callback, state=state) except Exception as e: logger.error("Error adding bybit API for user %s: %s", callback.from_user.id, e) await callback.message.answer( text="Произошла ошибка. Пожалуйста, попробуйте позже." ) @router_add_bybit_api.callback_query(F.data == "add_bybit_api") async def process_api_key(callback: CallbackQuery, state: FSMContext) -> None: """ Starts the FSM flow to add Bybit API keys. Sets the FSM state to prompt user to enter API Key. :param callback: CallbackQuery object. :param state: FSMContext for managing user state. """ try: await state.clear() await state.set_state(AddBybitApiState.api_key_state) await callback.answer() await callback.message.answer(text="Введите API Key:") except Exception as e: logger.error("Error adding bybit API for user %s: %s", callback.from_user.id, e) await callback.message.answer( text="Произошла ошибка. Пожалуйста, попробуйте позже." ) @router_add_bybit_api.message(AddBybitApiState.api_key_state) async def process_secret_key(message: Message, state: FSMContext) -> None: """ Receives the API Key input from the user, stores it in FSM context, then sets state to collect Secret Key. :param message: Message object with user's input. :param state: FSMContext for managing user state. """ try: api_key = message.text await state.update_data(api_key=api_key) await state.set_state(AddBybitApiState.api_secret_state) await message.answer(text="Введите Secret Key:") except Exception as e: logger.error("Error adding bybit API for user %s: %s", message.from_user.id, e) await message.answer(text="Произошла ошибка. Пожалуйста, попробуйте позже.") @router_add_bybit_api.message(AddBybitApiState.api_secret_state) async def add_bybit_api(message: Message, state: FSMContext) -> None: """ Receives the Secret Key input, stores it, saves both API keys in the database, clears FSM state and confirms success to the user. :param message: Message object with user's input. :param state: FSMContext for managing user state. """ try: api_secret = message.text api_key = (await state.get_data()).get("api_key") await state.update_data(api_secret=api_secret) if not api_key or not api_secret: await message.answer("Введите корректные данные.") return result = await rq.set_user_api( tg_id=message.from_user.id, api_key=api_key, api_secret=api_secret ) if result: await message.answer(text="Данные добавлены.", reply_markup=kbr.profile) await user_profile_bybit( tg_id=message.from_user.id, message=message, state=state ) logger.debug( "Bybit API added successfully for user: %s", message.from_user.id ) else: await message.answer(text="Произошла ошибка. Пожалуйста, попробуйте позже.") logger.error( "Error adding bybit API for user %s: %s", message.from_user.id, result ) await state.clear() except Exception as e: logger.error("Error adding bybit API for user %s: %s", message.from_user.id, e) await message.answer(text="Произошла ошибка. Пожалуйста, попробуйте позже.")