diff --git a/handlers/commands.py b/handlers/commands.py index 0df37208..c055e197 100644 --- a/handlers/commands.py +++ b/handlers/commands.py @@ -11,7 +11,7 @@ from bot import bot from config import DATABASE_URL from handlers.admin.admin import cmd_add_balance from handlers.keys.key_management import handle_key_name_input -from handlers.payment.yookassa_pay import ReplenishBalanceState, process_custom_amount_input +from handlers.payments.yookassa_pay import ReplenishBalanceState, process_custom_amount_input from handlers.profile import process_callback_view_profile from handlers.start import start_command from handlers.texts import TRIAL @@ -30,9 +30,9 @@ class Form(StatesGroup): async def backup_command(message: Message): from backup import backup_database - await message.answer("Запускаю бэкап базы данных...") + await message.answer("🔄 Инициализация резервного копирования базы данных...") await backup_database() - await message.answer("Бэкап завершен и отправлен админу.") + await message.answer("✅ Бэкап базы данных успешно завершен и отправлен администратору.") @router.message(Command("start")) @@ -62,34 +62,38 @@ async def handle_send_trial_command(message: types.Message, state: FSMContext): ) if records: + success_count = 0 + error_count = 0 + blocked_count = 0 + for record in records: tg_id = record["tg_id"] trial_message = TRIAL try: await bot.send_message(chat_id=tg_id, text=trial_message) + success_count += 1 except Exception as e: if "Forbidden: bot was blocked by the user" in str(e): - logger.info( - f"Бот заблокирован пользователем с tg_id: {tg_id}" - ) + blocked_count += 1 + logger.info(f"🚫 Бот заблокирован пользователем с tg_id: {tg_id}") else: - logger.error( - f"Ошибка при отправке сообщения пользователю {tg_id}: {e}" - ) + error_count += 1 + logger.error(f"❌ Ошибка при отправке сообщения пользователю {tg_id}: {e}") await message.answer( - "Сообщения о пробном периоде отправлены всем пользователям с не использованным ключом." + f"📊 Результаты рассылки пробных периодов:\n" + f"✅ Успешно отправлено: {success_count}\n" + f"🚫 Заблокировано: {blocked_count}\n" + f"❌ Ошибок: {error_count}" ) else: - await message.answer( - "Нет пользователей с не использованными пробными ключами." - ) + await message.answer("📭 Нет пользователей с неиспользованными пробными ключами.") finally: await conn.close() except Exception as e: - await message.answer(f"Ошибка при отправке сообщений: {e}") + await message.answer(f"❗ Ошибка при отправке сообщений: {e}") @router.message(Command("send_to_all"), IsAdminFilter()) @@ -97,9 +101,8 @@ async def send_message_to_all_clients( message: types.Message, state: FSMContext, from_panel=False ): if from_panel: - await message.answer( - "Введите текст сообщения, который вы хотите отправить всем клиентам:" + "✍️ Введите текст сообщения, который вы хотите отправить всем клиентам:" ) await state.set_state(Form.waiting_for_message) @@ -115,19 +118,30 @@ async def process_message_to_all( conn = await asyncpg.connect(DATABASE_URL) tg_ids = await conn.fetch("SELECT tg_id FROM connections") + total_users = len(tg_ids) + success_count = 0 + error_count = 0 + for record in tg_ids: tg_id = record["tg_id"] try: await bot.send_message(chat_id=tg_id, text=text_message) + success_count += 1 except Exception as e: + error_count += 1 logger.error( - f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя." + f"❌ Ошибка при отправке сообщения пользователю {tg_id}: {e}" ) - await message.answer("Сообщение было отправлено всем клиентам.") + await message.answer( + f"📤 Рассылка завершена:\n" + f"👥 Всего пользователей: {total_users}\n" + f"✅ Успешно отправлено: {success_count}\n" + f"❌ Не доставлено: {error_count}" + ) except Exception as e: - logger.error(f"Ошибка при подключении к базе данных: {e}") - await message.answer("Произошла ошибка при отправке сообщения.") + logger.error(f"❗ Ошибка при подключении к базе данных: {e}") + await message.answer("❌ Произошла ошибка при отправке сообщения.") finally: await conn.close() diff --git a/handlers/keys/key_management.py b/handlers/keys/key_management.py index 82d7c9a6..2e219bb4 100644 --- a/handlers/keys/key_management.py +++ b/handlers/keys/key_management.py @@ -135,7 +135,7 @@ async def handle_key_name_input(message: Message, state: FSMContext): if existing_key: await message.bot.send_message( tg_id, - "❌ Это имя уже используется. Пожалуйста, выберите другое имя для ключа.", + "❌ Упс! Это имя уже используется. Выберите другое уникальное название для ключа.", ) await state.set_state(Form.waiting_for_key_name) return @@ -168,7 +168,7 @@ async def handle_key_name_input(message: Message, state: FSMContext): keyboard = InlineKeyboardMarkup(inline_keyboard=[[replenish_button]]) await message.bot.send_message( tg_id, - "❗️ Недостаточно средств на балансе для создания подписки на новое устройство.", + "💳 Недостаточно средств для создания подписки на новое устройство. Пополните баланс в личном кабинете.", reply_markup=keyboard, ) await state.clear() @@ -181,7 +181,7 @@ async def handle_key_name_input(message: Message, state: FSMContext): public_link = f"{PUBLIC_LINK}{email}" button_profile = InlineKeyboardButton( - text="👤 Мой профиль", callback_data="view_profile" + text="👤 Личный кабинет", callback_data="view_profile" ) button_iphone = InlineKeyboardButton( text="🍏 Подключить", url=f"{APP_URL}/?url=v2raytun://import/{public_link}" @@ -210,7 +210,7 @@ async def handle_key_name_input(message: Message, state: FSMContext): remaining_time = expiry_time - current_time days = remaining_time.days key_message = key_message_success( - public_link, f"Оставшееся время ключа: {days} день" + public_link, f"⏳ Осталось дней: {days} 📅" ) await message.bot.send_message( diff --git a/handlers/keys/keys.py b/handlers/keys/keys.py index f9979126..24c7efe1 100644 --- a/handlers/keys/keys.py +++ b/handlers/keys/keys.py @@ -52,8 +52,8 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery): inline_keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons) response_message = ( - "Это ваши устройства:\n\n" - "Нажмите на имя устройства для управления его подпиской." + "🔑 Список ваших устройств\n\n" + "👆 Выберите устройство для управления подпиской:" ) await bot.delete_message( @@ -138,7 +138,7 @@ async def process_callback_view_key(callback_query: types.CallbackQuery): time_left = expiry_date - current_date if time_left.total_seconds() <= 0: - days_left_message = "Ключ истек." + days_left_message = "🕒 Статус подписки:\n🔴 Истекла\nОсталось часов: 0" elif time_left.days > 0: days_left_message = f"Осталось дней: {time_left.days}" else: @@ -578,7 +578,7 @@ async def process_callback_renew_plan(callback_query: types.CallbackQuery): text="Пополнить баланс", callback_data="pay" ) view_profile = types.InlineKeyboardButton( - text="👤 Мой профиль", callback_data="view_profile" + text="👤 Личный кабинет", callback_data="view_profile" ) keyboard = types.InlineKeyboardMarkup( inline_keyboard=[[replenish_button], [view_profile]] diff --git a/handlers/notifications.py b/handlers/notifications.py index 339022c4..ecdf56f4 100644 --- a/handlers/notifications.py +++ b/handlers/notifications.py @@ -112,7 +112,7 @@ async def notify_10h_keys( ], [ types.InlineKeyboardButton( - text="👤 Мой профиль", callback_data="view_profile" + text="👤 Личный кабинет", callback_data="view_profile" ) ], ] @@ -190,7 +190,7 @@ async def notify_24h_keys( ], [ types.InlineKeyboardButton( - text="👤 Мой профиль", callback_data="view_profile" + text="👤 Личный кабинет", callback_data="view_profile" ) ], ] @@ -248,9 +248,13 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time: f"Время истечения ключа: {expiry_time} (дата: {expiry_date}), Текущее время: {current_date}, Оставшееся время: {time_left}" ) - message_expired = f"Ваша подписка {email} истекла и была удалена!\n\n Перейдите в профиль для создания нового ключа" + message_expired = ( + "❌ Ваша подписка {email} истекла и была удалена!\n\n" + "🔍 Перейдите в профиль для создания нового ключа.\n" + "💡 Не откладывайте подключение VPN!" + ) button_profile = types.InlineKeyboardButton( - text="👤 Мой профиль", callback_data="view_profile" + text="👤 Личный кабинет", callback_data="view_profile" ) keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[button_profile]]) diff --git a/handlers/pay.py b/handlers/pay.py index eac3673b..1e158842 100644 --- a/handlers/pay.py +++ b/handlers/pay.py @@ -17,36 +17,39 @@ async def handle_pay(callback_query: CallbackQuery): if YOOKASSA_ENABLE: builder.row( InlineKeyboardButton( - text="💳 Пополнить баланс ЯКассой", + text="💳 ЯКасса: быстрый перевод", callback_data="pay_yookassa", ) ) if FREEKASSA_ENABLE: builder.row( InlineKeyboardButton( - text="💳 Пополнить баланс Freekassa", + text="🌐 FreeKassa: множество способов", callback_data="pay_freekassa", ) ) if CRYPTO_BOT_ENABLE: builder.row( InlineKeyboardButton( - text="💳 Пополнить баланс CryptoBot", + text="💰 CryptoBot: криптовалюта", callback_data="pay_cryptobot", ) ) if STARS_ENABLE: builder.row( InlineKeyboardButton( - text="💳 Пополнить баланс Звездами", + text="⭐ Оплата Звездами", callback_data="pay_stars", ) ) - builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="view_profile")) + builder.row(InlineKeyboardButton(text="⬅️ Вернуться в профиль", callback_data="view_profile")) await callback_query.message.answer( - "Выберите удобный вариант оплаты", + "💸 Выберите удобный способ пополнения баланса:\n\n" + "• Быстро и безопасно\n" + "• Поддержка разных платежных систем\n" + "• Моментальное зачисление средств 🚀", parse_mode="HTML", reply_markup=builder.as_markup(), ) diff --git a/handlers/profile.py b/handlers/profile.py index ce92152f..77df7759 100644 --- a/handlers/profile.py +++ b/handlers/profile.py @@ -32,14 +32,14 @@ async def process_callback_view_profile( if key_count == 0: profile_message += ( - "\nНажмите ➕Устройство снизу, чтобы добавить устройство в VPN" + "\n🔧 Нажмите кнопку ➕ Устройство, чтобы настроить VPN-подключение" ) builder = InlineKeyboardBuilder() builder.row(InlineKeyboardButton(text="📢 Наш канал", url=CHANNEL_URL)) builder.row( InlineKeyboardButton(text="➕ Устройство", callback_data="create_key"), - InlineKeyboardButton(text="📱 Мои устр-ва", callback_data="view_keys"), + InlineKeyboardButton(text="📱 Мои устройства", callback_data="view_keys"), ) builder.row( InlineKeyboardButton( @@ -48,15 +48,16 @@ async def process_callback_view_profile( ) ) builder.row( - InlineKeyboardButton(text="👥 Пригласить", callback_data="invite"), + InlineKeyboardButton(text="👥 Пригласить друзей", callback_data="invite"), InlineKeyboardButton(text="📘 Инструкции", callback_data="instructions"), ) - builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="back_to_menu")) + builder.row(InlineKeyboardButton(text="⬅️ Главное меню", callback_data="back_to_menu")) try: await callback_query.message.delete() except Exception as e: - logger.error(f"Ошибка при удалении сообщения: {e}") + logger.error(f"❗ Ошибка при удалении сообщения: {e}") + if os.path.isfile(image_path): with open(image_path, "rb") as image_file: await bot.send_photo( @@ -75,7 +76,7 @@ async def process_callback_view_profile( ) except Exception as e: - await bot.send_message(chat_id, f"❗️ Ошибка при получении данных профиля: {e}") + await bot.send_message(chat_id, f"❗️ Не удалось загрузить профиль. Техническая ошибка: {e}") await callback_query.answer() @@ -90,7 +91,7 @@ async def invite_handler(callback_query: types.CallbackQuery): invite_message = invite_message_send(referral_link, referral_stats) builder = InlineKeyboardBuilder() - builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="view_profile")) + builder.row(InlineKeyboardButton(text="⬅️ Вернуться в профиль", callback_data="view_profile")) await callback_query.message.delete() diff --git a/handlers/start.py b/handlers/start.py index 94ef8540..a69b542d 100644 --- a/handlers/start.py +++ b/handlers/start.py @@ -25,13 +25,13 @@ async def send_welcome_message(chat_id: int, trial_status: int): InlineKeyboardButton(text="🔗 Подключить VPN", callback_data="connect_vpn") ) builder.row( - InlineKeyboardButton(text="👤 Мой профиль", callback_data="view_profile") + InlineKeyboardButton(text="👤 Личный кабинет", callback_data="view_profile") ) builder.row( - InlineKeyboardButton(text="📞 Поддержка", url=SUPPORT_CHAT_URL), - InlineKeyboardButton(text="📢 Наш канал", url=CHANNEL_URL), + InlineKeyboardButton(text="📞 Техническая поддержка", url=SUPPORT_CHAT_URL), + InlineKeyboardButton(text="📢 Официальный канал", url=CHANNEL_URL), ) - builder.row(InlineKeyboardButton(text="🔒 О VPN", callback_data="about_vpn")) + builder.row(InlineKeyboardButton(text="🌐 О нашем VPN", callback_data="about_vpn")) if os.path.isfile(image_path): with open(image_path, "rb") as image_from_buffer: @@ -95,34 +95,35 @@ async def handle_connect_vpn(callback_query: CallbackQuery): await conn.close() key_message = ( - f"Ваш ключ доступа:\n
{trial_key_info['key']}
\n\n" - f"Инструкции:\n{INSTRUCTIONS_TRIAL}" + f"🔑 Ваш персональный ключ доступа:\n" + f"
{trial_key_info['key']}
\n\n" + f"📋 Быстрая инструкция по подключению:\n{INSTRUCTIONS_TRIAL}" ) builder = InlineKeyboardBuilder() builder.row( - InlineKeyboardButton(text="👤 Мой профиль", callback_data="view_profile") + InlineKeyboardButton(text="👤 Личный кабинет", callback_data="view_profile") ) builder.row( InlineKeyboardButton( - text="🍏 Скачать", - url="https://apps.apple.com/ru/app/v2raytun/id6476628951", + text="🍏 Скачать для iOS", + url="https://apps.apple.com/ru/app/v2raytun/id6476628951" ), InlineKeyboardButton( - text="🤖 Скачать", - url="https://play.google.com/store/apps/details?id=com.v2raytun.android&hl=ru", + text="🤖 Скачать для Android", + url="https://play.google.com/store/apps/details?id=com.v2raytun.android&hl=ru" ), ) builder.row( InlineKeyboardButton( - text="🍏 Подключить", - url=f'{APP_URL}/?url=v2raytun://import/{trial_key_info["key"]}', + text="🍏 Подключить на iOS", + url=f'{APP_URL}/?url=v2raytun://import/{trial_key_info["key"]}' ), InlineKeyboardButton( - text="🤖 Подключить", - url=f'{APP_URL}/?url=v2raytun://import-sub?url={trial_key_info["key"]}', + text="🤖 Подключить на Android", + url=f'{APP_URL}/?url=v2raytun://import-sub?url={trial_key_info["key"]}' ), )