я не пойму, что не так в этом коде, когда я добавляю ключ апи, ключ добавляется, все отоично, но в логе ошибки:



Oct 14 23:53:54 vps1707806210 python[37865]: 2024-10-14 23:53:54,023 - bot.api - INFO - Ответ баланса: BAD_KEY
Oct 14 23:53:54 vps1707806210 python[37865]: 2024-10-14 23:53:54,128 - aiogram.event - INFO - Update id=480221264 is handled. Duration 350 ms by bot id=7625597085
Oct 14 23:53:57 vps1707806210 python[37865]: 2024-10-14 23:53:57,723 - bot.handlers.settings - INFO - Пользователь 389669884 ввёл API ключ.
Oct 14 23:53:57 vps1707806210 python[37865]: 2024-10-14 23:53:57,894 - bot.api - INFO - Запрос баланса с валютой: 643
Oct 14 23:53:58 vps1707806210 python[37865]: 2024-10-14 23:53:58,062 - bot.api - INFO - Ответ баланса: BAD_KEY
Oct 14 23:53:58 vps1707806210 python[37865]: 2024-10-14 23:53:58,314 - aiogram.event - INFO - Update id=480221265 is handled. Duration 592 ms by bot id=7625597085
Oct 14 23:54:06 vps1707806210 python[37865]: 2024-10-14 23:54:06,763 - aiogram.event - INFO - Update id=480221266 is handled. Duration 129 ms by bot id=7625597085
Oct 14 23:54:07 vps1707806210 python[37865]: 2024-10-14 23:54:07,906 - aiogram.event - INFO - Update id=480221267 is handled. Duration 134 ms by bot id=7625597085
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,281 - bot.handlers.settings - INFO - Пользователь 389669884 ввёл API ключ.
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,348 - bot.api - INFO - Запрос баланса с валютой: 643
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,533 - bot.api - INFO - Ответ баланса: ACCESS_BALANCE:1.1137
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,536 - bot.data - INFO - Данные пользователей успешно сохранены.
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,536 - bot.data - INFO - API ключ для пользователя 389669884 сохранён.
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,665 - bot.utils - WARNING - Сообщение не может быть отредактировано: Telegram server says - Bad Request: message to edit not found. Пробуем отправить новое сообщение.
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,716 - bot.utils - WARNING - Не удалось удалить сообщение: Telegram server says - Bad Request: message to delete not found
Oct 14 23:54:09 vps1707806210 python[37865]: 2024-10-14 23:54:09,787 - aiogram.event - INFO - Update id=480221268 is handled. Duration 508 ms by bot id=7625597085





import logging
from aiogram import Dispatcher, types, F
from aiogram.fsm.context import FSMContext
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.state import State, StatesGroup
import os

from ..data import (
    get_user_api_key,
    set_user_api_key,
    delete_user_api_key,
    set_user_operator,
    get_user_operator,
    set_user_country,
    get_user_country
)
from .start import send_main_menu
from ..api import SmsHubAPI
from ..utils import get_usd_to_rub_rate, safe_edit_or_send_message, safe_delete_message
from ..constants import OPERATOR_DISPLAY_NAMES, COUNTRIES, COUNTRY_OPERATORS

logger = logging.getLogger(__name__)

class UserSettings(StatesGroup):
    entering_api_key = State()

class OperatorSettings(StatesGroup):
    selecting_operator = State()

class CountrySettings(StatesGroup):
    selecting_country = State()

async def handle_callback_answer(callback_query: types.CallbackQuery):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

async def settings_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    await show_settings_menu(callback_query.message, state, callback_query.from_user.id)

async def show_settings_menu(message: types.Message, state: FSMContext, user_id: int):
    user_api_key = get_user_api_key(user_id)
    user_operator = get_user_operator(user_id) or "any"
    operator_display_name = OPERATOR_DISPLAY_NAMES.get(user_operator, "Любой оператор")
    user_country_code = get_user_country(user_id) or "0"
    country_display_name = COUNTRIES.get(user_country_code, user_country_code)

    keyboard = create_settings_keyboard(user_api_key)
    message_text = build_settings_message(user_api_key, operator_display_name, country_display_name)

    sent_message = await safe_edit_or_send_message(
        message=message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard,
        parse_mode="Markdown"
    )
    
    if sent_message:
        await state.update_data(last_message_id=sent_message.message_id)

    await state.set_state(None)

def create_settings_keyboard(user_api_key):
    keyboard = InlineKeyboardBuilder()
    if user_api_key:
        keyboard.button(text="✏️ Изменить API ключ", callback_data="edit_api_key")
        keyboard.button(text="❌ Удалить API ключ", callback_data="delete_api_key")
    else:
        keyboard.button(text="➕ Добавить API ключ", callback_data="add_api_key")
    keyboard.button(text="✏️ Изменить оператора", callback_data="edit_operator")
    keyboard.button(text="✏️ Изменить страну", callback_data="edit_country")
    keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
    keyboard.adjust(1)
    return keyboard.as_markup()

def build_settings_message(user_api_key, operator_display_name, country_display_name):
    api_key_info = f"Ваш текущий API ключ: `{user_api_key}`\n" if user_api_key else "API ключ не настроен.\n"
    return api_key_info + f"Текущий оператор: `{operator_display_name}`\nТекущая страна: `{country_display_name}`"

async def input_api_key_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    await show_input_api_key_instructions(callback_query.message, state)

async def show_input_api_key_instructions(message: types.Message, state: FSMContext):
    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="🔙 Назад", callback_data="cancel_settings")
    keyboard.adjust(1)
    instruction_text = (
        "<b>Введите ваш API ключ для работы с сервисом:</b>\n\n"
        "<blockquote expandable>"
        "<b>Получение вашего API ключа</b>\n"
        "Чтобы начать использовать API, вам нужно получить ваш уникальный API ключ. Следуйте этим шагам:\n"
        "1. Перейдите по <a href='https://smshub.org/ru/settings'>ссылке на настройки SMSHUB</a>.\n"
        "2. Найдите кнопку \"Сгенерировать новый ключ\" и нажмите на неё.\n"
        "3. Ваша почта, на которую был зарегистрирован аккаунт, получит сообщение с вашим новым API ключом.\n"
        "4. Скопируйте ключ из письма.\n"
        "</blockquote>\n"
        "<blockquote expandable>"
        "<b>Ввод вашего API ключа</b>\n"
        "После получения ключа, вы можете ввести его в нашем боте. Для этого выполните следующие действия:\n"
        "1. Откройте интерфейс бота, выберите меню настроек.\n"
        "2. Нажмите на кнопку \"➕ Добавить API ключ\", чтобы начать процесс.\n"
        "3. Когда бот запросит, вставьте ваш API ключ в текстовое поле.\n"
        "4. Нажмите \"Отправить\".\n"
        "Ваш ключ будет проверен, и если он корректен, бот сохранит его для дальнейшего использования."
        "</blockquote>\n\n"
        "<blockquote expandable>"
        "<b>Информация о безопасности</b>\n"
        "Не забывайте, что ваш API ключ должен оставаться конфиденциальным. Никому не сообщайте его, чтобы "
        "избежать несанкционированного доступа к вашим данным и услугам."
        "</blockquote>"
    )
    sent_message = await safe_edit_or_send_message(
        message=message,
        new_text=instruction_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="HTML",
        disable_web_page_preview=True
    )

    if sent_message:
        await state.update_data(last_message_id=sent_message.message_id)
    
    await state.set_state(UserSettings.entering_api_key)

async def delete_user_api_key_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    delete_user_api_key(callback_query.from_user.id)
    await show_settings_menu(callback_query.message, state, callback_query.from_user.id)

async def back_to_main_menu_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    await state.set_state(None)
    await send_main_menu(callback_query.message, state)

async def cancel_settings_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    await show_settings_menu(callback_query.message, state, callback_query.from_user.id)

async def set_user_api_key_handler(message: types.Message, state: FSMContext):
    user_api_key = message.text.strip()
    logger.info(f"Пользователь {message.from_user.id} ввёл API ключ.")
    smshub_api = SmsHubAPI(user_api_key)

    try:
        await message.delete()
    except Exception as e:
        logger.error(f"Ошибка при удалении сообщения: {e}")

    try:
        balance_response = await smshub_api.get_balance()
        if balance_response and balance_response.startswith("ACCESS_BALANCE:"):
            set_user_api_key(message.from_user.id, user_api_key)

            saved_api_key = get_user_api_key(message.from_user.id)
            if saved_api_key == user_api_key:
                data = await state.get_data()
                last_message_id = data.get('last_message_id')
                if last_message_id:
                    try:
                        await safe_delete_message(message.bot, message.chat.id, last_message_id)
                    except Exception as e:
                        logger.error(f"Ошибка при удалении сообщения: {e}")

                await show_settings_menu(message, state, message.from_user.id)
            else:
                await message.answer("Произошла ошибка при сохранении API ключа. Пожалуйста, попробуйте снова.")
                return

            await state.set_state(None)
        else:
            # Если ключ неверен, отредактировать предыдущее сообщение
            error_msg = "Неверный API ключ или ошибка при получении баланса."
            await safe_edit_or_send_message(
                message=message,
                new_text=error_msg,
                state=state,
                reply_markup=create_retry_keyboard()
            )

    except Exception as e:
        logger.error(f"Ошибка при обработке API ключа: {e}")

def create_retry_keyboard():
    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="🔄 Повторить ввод", callback_data="edit_api_key")
    keyboard.button(text="🔙 Назад", callback_data="cancel_settings")
    keyboard.adjust(1)
    return keyboard.as_markup()

async def select_operator_handler(callback_query: types.CallbackQuery, state: FSMContext, page: int = 0):
    await handle_callback_answer(callback_query)

    data = await state.get_data()
    user_country_code = data.get('selected_country_code', '0')
    operator_list = COUNTRY_OPERATORS.get(user_country_code, ["any"])

    items_per_page = 10
    start = page * items_per_page
    end = start + items_per_page

    keyboard = InlineKeyboardBuilder()
    for op in operator_list[start:end]:
        display_name = OPERATOR_DISPLAY_NAMES.get(op, op)
        keyboard.button(text=display_name, callback_data=f"operator:{op}")
    keyboard.adjust(2)

    add_navigation_buttons(keyboard, page, len(operator_list), items_per_page, "operator_page", "cancel_operator_selection")

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text="Выберите оператора из списка:",
        state=state,
        reply_markup=keyboard.as_markup()
    )
    await state.set_state(OperatorSettings.selecting_operator)

async def operator_page_handler(callback_query: types.CallbackQuery, state: FSMContext):
    page = int(callback_query.data.split(':')[1])
    await select_operator_handler(callback_query, state, page)

async def cancel_operator_selection_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    await show_settings_menu(callback_query.message, state, callback_query.from_user.id)

async def operator_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    operator = callback_query.data.split(":")[1]
    set_user_operator(callback_query.from_user.id, operator)
    display_name = OPERATOR_DISPLAY_NAMES.get(operator, operator)
    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=f"Вы выбрали оператора: {display_name}",
        state=state
    )
    await show_settings_menu(callback_query.message, state, callback_query.from_user.id)

async def select_country_handler(callback_query: types.CallbackQuery, state: FSMContext, page: int = 0):
    await handle_callback_answer(callback_query)

    countries_list = list(COUNTRIES.items())
    items_per_page = 10
    start = page * items_per_page
    end = start + items_per_page

    keyboard = InlineKeyboardBuilder()
    for country_code, country_name in countries_list[start:end]:
        keyboard.button(text=country_name, callback_data=f"country:{country_code}")
    keyboard.adjust(2)

    add_navigation_buttons(keyboard, page, len(countries_list), items_per_page, "country_page", "cancel_country_selection")

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text="Выберите страну из списка:",
        state=state,
        reply_markup=keyboard.as_markup()
    )
    await state.set_state(CountrySettings.selecting_country)

async def country_page_handler(callback_query: types.CallbackQuery, state: FSMContext):
    page = int(callback_query.data.split(':')[1])
    await select_country_handler(callback_query, state, page)

async def country_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)

    country_code = callback_query.data.split(":")[1]
    set_user_country(callback_query.from_user.id, country_code)
    country_name = COUNTRIES.get(country_code, country_code)

    await state.update_data(selected_country_code=country_code)

    current_operator = get_user_operator(callback_query.from_user.id) or "any"
    available_operators = COUNTRY_OPERATORS.get(country_code, [])

    if current_operator not in available_operators:
        set_user_operator(callback_query.from_user.id, "any")

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=f"Вы выбрали страну: {country_name}",
        state=state
    )
    await show_settings_menu(callback_query, state, callback_query.from_user.id)

async def cancel_country_selection_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await handle_callback_answer(callback_query)
    await show_settings_menu(callback_query, state, callback_query.from_user.id)

def add_navigation_buttons(keyboard, page, item_count, items_per_page, page_callback, cancel_callback):
    nav_buttons = []
    if page > 0:
        nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"{page_callback}:{page - 1}"))
    if (page + 1) * items_per_page < item_count:
        nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперёд", callback_data=f"{page_callback}:{page + 1}"))
    if nav_buttons:
        keyboard.row(*nav_buttons)
    keyboard.row(types.InlineKeyboardButton(text="🔙 Назад", callback_data=cancel_callback))

# Обработчик ошибок
async def errors_handler(update: types.Update, exception: Exception):
    logger.error(f"Ошибка в обновлении {update} с исключением: {exception}")
    return True

def register_settings_handlers(dp: Dispatcher):
    dp.callback_query.register(settings_handler, F.data == "settings")
    dp.callback_query.register(input_api_key_handler, F.data.in_({"edit_api_key", "add_api_key"}))
    dp.callback_query.register(delete_user_api_key_handler, F.data == "delete_api_key")
    dp.callback_query.register(back_to_main_menu_handler, F.data == "back_to_main_menu")
    dp.callback_query.register(cancel_settings_handler, F.data == "cancel_settings")
    dp.message.register(set_user_api_key_handler, UserSettings.entering_api_key)
    dp.callback_query.register(select_operator_handler, F.data == "edit_operator")
    dp.callback_query.register(cancel_operator_selection_handler, F.data == "cancel_operator_selection")
    dp.callback_query.register(operator_selected_handler, OperatorSettings.selecting_operator, F.data.startswith("operator:"))
    dp.callback_query.register(operator_page_handler, OperatorSettings.selecting_operator, F.data.startswith("operator_page:"))
    dp.callback_query.register(select_country_handler, F.data == "edit_country")
    dp.callback_query.register(country_selected_handler, CountrySettings.selecting_country, F.data.startswith("country:"))
    dp.callback_query.register(cancel_country_selection_handler, F.data == "cancel_country_selection")
    dp.callback_query.register(country_page_handler, CountrySettings.selecting_country, F.data.startswith("country_page:"))
    dp.errors.register(errors_handler)