Полная реструктуризация. Тексты все в texts.py
This commit is contained in:
+2
-1
@@ -8,4 +8,5 @@
|
|||||||
/database.db
|
/database.db
|
||||||
/backup_pg.sh
|
/backup_pg.sh
|
||||||
/config copy.py
|
/config copy.py
|
||||||
/docker-compose.yml
|
/docker-compose.yml
|
||||||
|
__pycache__
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ storage = MemoryStorage()
|
|||||||
dp = Dispatcher(bot=bot, storage=storage)
|
dp = Dispatcher(bot=bot, storage=storage)
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
from handlers import (backup_handler, key_management, keys, notifications, pay,
|
from handlers.admin import admin
|
||||||
profile, start, admin, commands)
|
from handlers.keys import key_management, keys
|
||||||
|
from handlers import (notifications, pay,
|
||||||
|
profile, start, commands)
|
||||||
|
|
||||||
dp.include_router(commands.router)
|
dp.include_router(commands.router)
|
||||||
dp.include_router(start.router)
|
dp.include_router(start.router)
|
||||||
@@ -18,5 +20,4 @@ dp.include_router(keys.router)
|
|||||||
dp.include_router(key_management.router)
|
dp.include_router(key_management.router)
|
||||||
dp.include_router(pay.router)
|
dp.include_router(pay.router)
|
||||||
dp.include_router(notifications.router)
|
dp.include_router(notifications.router)
|
||||||
dp.include_router(backup_handler.router)
|
|
||||||
dp.include_router(admin.router)
|
dp.include_router(admin.router)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
from aiogram import Router, types
|
from aiogram import Router, types
|
||||||
from aiogram.filters import Command
|
from aiogram.filters import Command
|
||||||
from database import add_balance_to_client, get_balance, check_connection_exists # Импорт необходимых функций
|
from database import add_balance_to_client, get_balance, check_connection_exists
|
||||||
from config import ADMIN_ID
|
from config import ADMIN_ID
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
from aiogram import Router
|
|
||||||
from aiogram.filters import Command
|
|
||||||
from aiogram.types import Message
|
|
||||||
from config import ADMIN_ID
|
|
||||||
|
|
||||||
router = Router()
|
|
||||||
|
|
||||||
@router.message(Command('backup'))
|
|
||||||
async def backup_command(message: Message):
|
|
||||||
if message.from_user.id != ADMIN_ID:
|
|
||||||
await message.answer("У вас нет прав для выполнения этой команды.")
|
|
||||||
return
|
|
||||||
|
|
||||||
from backup import backup_database
|
|
||||||
await message.answer("Запускаю бэкап базы данных...")
|
|
||||||
await backup_database()
|
|
||||||
await message.answer("Бэкап завершен и отправлен админу.")
|
|
||||||
+14
-3
@@ -6,13 +6,13 @@ import asyncpg
|
|||||||
|
|
||||||
from bot import bot
|
from bot import bot
|
||||||
from config import ADMIN_ID, DATABASE_URL
|
from config import ADMIN_ID, DATABASE_URL
|
||||||
from handlers.backup_handler import backup_command
|
|
||||||
from handlers.pay import ReplenishBalanceState, process_custom_amount_input
|
from handlers.pay import ReplenishBalanceState, process_custom_amount_input
|
||||||
from handlers.profile import process_callback_view_profile
|
from handlers.profile import process_callback_view_profile
|
||||||
from handlers.start import start_command
|
from handlers.start import start_command
|
||||||
from handlers.texts import TRIAL
|
from handlers.texts import TRIAL
|
||||||
from handlers.admin import cmd_add_balance
|
from handlers.admin.admin import cmd_add_balance
|
||||||
from handlers.key_management import handle_key_name_input
|
from handlers.keys.key_management import handle_key_name_input
|
||||||
|
from aiogram.types import Message
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
@@ -22,6 +22,17 @@ class Form(StatesGroup):
|
|||||||
viewing_profile = State()
|
viewing_profile = State()
|
||||||
waiting_for_message = State()
|
waiting_for_message = State()
|
||||||
|
|
||||||
|
@router.message(Command('backup'))
|
||||||
|
async def backup_command(message: Message):
|
||||||
|
if message.from_user.id != ADMIN_ID:
|
||||||
|
await message.answer("У вас нет прав для выполнения этой команды.")
|
||||||
|
return
|
||||||
|
|
||||||
|
from backup import backup_database
|
||||||
|
await message.answer("Запускаю бэкап базы данных...")
|
||||||
|
await backup_database()
|
||||||
|
await message.answer("Бэкап завершен и отправлен админу.")
|
||||||
|
|
||||||
@router.message(Command('start'))
|
@router.message(Command('start'))
|
||||||
async def handle_start(message: types.Message, state: FSMContext):
|
async def handle_start(message: types.Message, state: FSMContext):
|
||||||
await start_command(message)
|
await start_command(message)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
@@ -1,6 +1,7 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from bot import dp
|
||||||
import asyncpg
|
import asyncpg
|
||||||
from aiogram import F, Router
|
from aiogram import F, Router
|
||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
@@ -9,12 +10,11 @@ from aiogram.types import (CallbackQuery, InlineKeyboardButton,
|
|||||||
InlineKeyboardMarkup, Message)
|
InlineKeyboardMarkup, Message)
|
||||||
|
|
||||||
from auth import link, login_with_credentials
|
from auth import link, login_with_credentials
|
||||||
from bot import bot, dp
|
|
||||||
from client import add_client
|
from client import add_client
|
||||||
from config import (ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL,
|
from config import (ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL,
|
||||||
SERVERS)
|
SERVERS)
|
||||||
from database import add_connection, get_balance, store_key, update_balance
|
from database import add_connection, get_balance, store_key, update_balance
|
||||||
from handlers.instructions import send_instructions
|
from handlers.instructions.instructions import send_instructions
|
||||||
from handlers.profile import process_callback_view_profile
|
from handlers.profile import process_callback_view_profile
|
||||||
from handlers.texts import KEY, KEY_TRIAL, NULL_BALANCE, key_message_success
|
from handlers.texts import KEY, KEY_TRIAL, NULL_BALANCE, key_message_success
|
||||||
from handlers.utils import sanitize_key_name
|
from handlers.utils import sanitize_key_name
|
||||||
@@ -121,7 +121,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
|
|||||||
key_name = sanitize_key_name(message.text)
|
key_name = sanitize_key_name(message.text)
|
||||||
|
|
||||||
if not key_name:
|
if not key_name:
|
||||||
await message.bot.send_message(tg_id, "📝 Пожалуйста, назовите профиль на английском языке.")
|
await message.bot.send_message(tg_id, "📝 Пожалуйста, назовите ключ устройства на английском языке.")
|
||||||
return
|
return
|
||||||
|
|
||||||
data = await state.get_data()
|
data = await state.get_data()
|
||||||
@@ -164,7 +164,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
|
|||||||
if not response.get("success", True):
|
if not response.get("success", True):
|
||||||
error_msg = response.get("msg", "Неизвестная ошибка.")
|
error_msg = response.get("msg", "Неизвестная ошибка.")
|
||||||
if "Duplicate email" in error_msg:
|
if "Duplicate email" in error_msg:
|
||||||
await message.bot.send_message(tg_id, "❌ Этот email уже используется. Пожалуйста, выберите другое имя для ключа.")
|
await message.bot.send_message(tg_id, "❌ Это имя уже используется. Пожалуйста, выберите другое имя для ключа.")
|
||||||
await state.set_state(Form.waiting_for_key_name)
|
await state.set_state(Form.waiting_for_key_name)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
@@ -11,6 +11,7 @@ from config import ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL, SERVERS
|
|||||||
from database import get_balance, update_balance
|
from database import get_balance, update_balance
|
||||||
from handlers.texts import NO_KEYS
|
from handlers.texts import NO_KEYS
|
||||||
from handlers.texts import key_message, key_relocated
|
from handlers.texts import key_message, key_relocated
|
||||||
|
from handlers.texts import RENEWAL_PLANS, INSUFFICIENT_FUNDS_MSG, KEY_NOT_FOUND_MSG, SUCCESS_RENEWAL_MSG, ERROR_RENEWAL_MSG, PLAN_SELECTION_MSG
|
||||||
|
|
||||||
locale.setlocale(locale.LC_TIME, 'ru_RU.UTF-8')
|
locale.setlocale(locale.LC_TIME, 'ru_RU.UTF-8')
|
||||||
|
|
||||||
@@ -159,17 +160,15 @@ async def process_callback_renew_key(callback_query: types.CallbackQuery):
|
|||||||
expiry_time = record['expiry_time']
|
expiry_time = record['expiry_time']
|
||||||
current_time = datetime.utcnow().timestamp() * 1000
|
current_time = datetime.utcnow().timestamp() * 1000
|
||||||
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
|
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
|
||||||
[types.InlineKeyboardButton(text='📅 1 месяц (100 руб.)', callback_data=f'renew_plan|1|{client_id}')],
|
[types.InlineKeyboardButton(text=f'📅 1 месяц ({RENEWAL_PLANS["1"]["price"]} руб.)', callback_data=f'renew_plan|1|{client_id}')],
|
||||||
[types.InlineKeyboardButton(text='📅 3 месяца (285 руб.)', callback_data=f'renew_plan|3|{client_id}')],
|
[types.InlineKeyboardButton(text=f'📅 3 месяца ({RENEWAL_PLANS["3"]["price"]} руб.)', callback_data=f'renew_plan|3|{client_id}')],
|
||||||
[types.InlineKeyboardButton(text='📅 6 месяцев (540 руб.)', callback_data=f'renew_plan|6|{client_id}')],
|
[types.InlineKeyboardButton(text=f'📅 6 месяцев ({RENEWAL_PLANS["6"]["price"]} руб.)', callback_data=f'renew_plan|6|{client_id}')],
|
||||||
[types.InlineKeyboardButton(text='📅 12 месяцев (1000 руб.)', callback_data=f'renew_plan|12|{client_id}')],
|
[types.InlineKeyboardButton(text=f'📅 12 месяцев ({RENEWAL_PLANS["12"]["price"]} руб.)', callback_data=f'renew_plan|12|{client_id}')],
|
||||||
[types.InlineKeyboardButton(text='🔙 Назад', callback_data='view_profile')]
|
[types.InlineKeyboardButton(text='🔙 Назад', callback_data='view_profile')]
|
||||||
])
|
])
|
||||||
|
|
||||||
balance = await get_balance(tg_id)
|
balance = await get_balance(tg_id)
|
||||||
response_message = (f"<b>Выберите план продления:</b>\n\n"
|
response_message = PLAN_SELECTION_MSG.format(balance=balance, expiry_date=datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S'))
|
||||||
f"💰 <b>Баланс:</b> {balance} руб.\n\n"
|
|
||||||
f"📅 <b>Текущая дата истечения ключа:</b> {datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S')}")
|
|
||||||
|
|
||||||
await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard, parse_mode="HTML")
|
await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard, parse_mode="HTML")
|
||||||
|
|
||||||
@@ -181,6 +180,7 @@ async def process_callback_renew_key(callback_query: types.CallbackQuery):
|
|||||||
|
|
||||||
await callback_query.answer()
|
await callback_query.answer()
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(lambda c: c.data.startswith('confirm_delete|'))
|
@router.callback_query(lambda c: c.data.startswith('confirm_delete|'))
|
||||||
async def process_callback_confirm_delete(callback_query: types.CallbackQuery):
|
async def process_callback_confirm_delete(callback_query: types.CallbackQuery):
|
||||||
tg_id = callback_query.from_user.id
|
tg_id = callback_query.from_user.id
|
||||||
@@ -222,7 +222,7 @@ async def process_callback_confirm_delete(callback_query: types.CallbackQuery):
|
|||||||
@router.callback_query(lambda c: c.data.startswith('renew_plan|'))
|
@router.callback_query(lambda c: c.data.startswith('renew_plan|'))
|
||||||
async def process_callback_renew_plan(callback_query: types.CallbackQuery):
|
async def process_callback_renew_plan(callback_query: types.CallbackQuery):
|
||||||
tg_id = callback_query.from_user.id
|
tg_id = callback_query.from_user.id
|
||||||
plan, client_id = callback_query.data.split('|')[1], callback_query.data.split('|')[2]
|
plan, client_id = callback_query.data.split('|')[1], callback_query.data.split('|')[2]
|
||||||
days_to_extend = 30 * int(plan)
|
days_to_extend = 30 * int(plan)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -241,14 +241,7 @@ async def process_callback_renew_plan(callback_query: types.CallbackQuery):
|
|||||||
else:
|
else:
|
||||||
new_expiry_time = int(expiry_time + timedelta(days=days_to_extend).total_seconds() * 1000)
|
new_expiry_time = int(expiry_time + timedelta(days=days_to_extend).total_seconds() * 1000)
|
||||||
|
|
||||||
if plan == '1':
|
cost = RENEWAL_PLANS[plan]['price']
|
||||||
cost = 100
|
|
||||||
elif plan == '3':
|
|
||||||
cost = 285
|
|
||||||
elif plan == '6':
|
|
||||||
cost = 540
|
|
||||||
elif plan == '12':
|
|
||||||
cost = 1000
|
|
||||||
|
|
||||||
balance = await get_balance(tg_id)
|
balance = await get_balance(tg_id)
|
||||||
if balance < cost:
|
if balance < cost:
|
||||||
@@ -256,7 +249,7 @@ async def process_callback_renew_plan(callback_query: types.CallbackQuery):
|
|||||||
back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_profile')
|
back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_profile')
|
||||||
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[replenish_button], [back_button]])
|
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[replenish_button], [back_button]])
|
||||||
|
|
||||||
await bot.edit_message_text("Недостаточно средств для продления ключа.", chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard)
|
await bot.edit_message_text(INSUFFICIENT_FUNDS_MSG, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard)
|
||||||
return
|
return
|
||||||
|
|
||||||
session = await login_with_credentials(server_id, ADMIN_USERNAME, ADMIN_PASSWORD)
|
session = await login_with_credentials(server_id, ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||||
@@ -265,14 +258,14 @@ async def process_callback_renew_plan(callback_query: types.CallbackQuery):
|
|||||||
if success:
|
if success:
|
||||||
await update_balance(tg_id, -cost)
|
await update_balance(tg_id, -cost)
|
||||||
await conn.execute('UPDATE keys SET expiry_time = $1 WHERE client_id = $2', new_expiry_time, client_id)
|
await conn.execute('UPDATE keys SET expiry_time = $1 WHERE client_id = $2', new_expiry_time, client_id)
|
||||||
response_message = f"Ваш ключ был успешно продлен на {days_to_extend // 30} месяц(-а)."
|
response_message = SUCCESS_RENEWAL_MSG.format(months=RENEWAL_PLANS[plan]['months'])
|
||||||
back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_profile')
|
back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_profile')
|
||||||
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[back_button]])
|
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[back_button]])
|
||||||
await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard)
|
await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard)
|
||||||
else:
|
else:
|
||||||
await bot.edit_message_text("Ошибка при продлении ключа.", chat_id=tg_id, message_id=callback_query.message.message_id)
|
await bot.edit_message_text(ERROR_RENEWAL_MSG, chat_id=tg_id, message_id=callback_query.message.message_id)
|
||||||
else:
|
else:
|
||||||
await bot.edit_message_text("Ключ не найден.", chat_id=tg_id, message_id=callback_query.message.message_id)
|
await bot.edit_message_text(KEY_NOT_FOUND_MSG, chat_id=tg_id, message_id=callback_query.message.message_id)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
await conn.close()
|
await conn.close()
|
||||||
@@ -294,7 +287,7 @@ async def process_callback_change_location(callback_query: types.CallbackQuery):
|
|||||||
try:
|
try:
|
||||||
for server_id, server in SERVERS.items():
|
for server_id, server in SERVERS.items():
|
||||||
count = await conn.fetchval('SELECT COUNT(*) FROM keys WHERE server_id = $1', server_id)
|
count = await conn.fetchval('SELECT COUNT(*) FROM keys WHERE server_id = $1', server_id)
|
||||||
percent_full = (count / 100) * 100
|
percent_full = (count / 60) * 100 if count <= 60 else 100
|
||||||
server_name = f"{server['name']} ({percent_full:.1f}%)"
|
server_name = f"{server['name']} ({percent_full:.1f}%)"
|
||||||
server_buttons.append([types.InlineKeyboardButton(text=server_name, callback_data=f'select_server&{server_id}&{client_id}')])
|
server_buttons.append([types.InlineKeyboardButton(text=server_name, callback_data=f'select_server&{server_id}&{client_id}')])
|
||||||
finally:
|
finally:
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import random
|
|
||||||
import asyncpg
|
import asyncpg
|
||||||
import uuid
|
import uuid
|
||||||
from config import DATABASE_URL, SERVERS, ADMIN_USERNAME, ADMIN_PASSWORD
|
from config import DATABASE_URL, SERVERS, ADMIN_USERNAME, ADMIN_PASSWORD
|
||||||
+20
-9
@@ -13,6 +13,7 @@ from config import YOOKASSA_SECRET_KEY, YOOKASSA_SHOP_ID
|
|||||||
from database import (add_connection, check_connection_exists, get_key_count,
|
from database import (add_connection, check_connection_exists, get_key_count,
|
||||||
update_balance)
|
update_balance)
|
||||||
from handlers.profile import process_callback_view_profile
|
from handlers.profile import process_callback_view_profile
|
||||||
|
from handlers.texts import PAYMENT_OPTIONS
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
@@ -59,10 +60,20 @@ async def process_callback_replenish_balance(callback_query: types.CallbackQuery
|
|||||||
await add_connection(tg_id, balance=0.0, trial=0)
|
await add_connection(tg_id, balance=0.0, trial=0)
|
||||||
|
|
||||||
amount_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
amount_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||||
[InlineKeyboardButton(text='100 RUB', callback_data='amount_100'), InlineKeyboardButton(text='300 RUB', callback_data='amount_300')],
|
[
|
||||||
[InlineKeyboardButton(text='600 RUB', callback_data='amount_600'), InlineKeyboardButton(text='1000 RUB', callback_data='amount_1000')],
|
InlineKeyboardButton(text=PAYMENT_OPTIONS[0]['text'], callback_data=PAYMENT_OPTIONS[0]['callback_data']),
|
||||||
[InlineKeyboardButton(text='💰 Ввести свою сумму', callback_data='enter_custom_amount')],
|
InlineKeyboardButton(text=PAYMENT_OPTIONS[1]['text'], callback_data=PAYMENT_OPTIONS[1]['callback_data'])
|
||||||
[InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')]
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(text=PAYMENT_OPTIONS[2]['text'], callback_data=PAYMENT_OPTIONS[2]['callback_data']),
|
||||||
|
InlineKeyboardButton(text=PAYMENT_OPTIONS[3]['text'], callback_data=PAYMENT_OPTIONS[3]['callback_data'])
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(text=PAYMENT_OPTIONS[4]['text'], callback_data=PAYMENT_OPTIONS[4]['callback_data'])
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(text=PAYMENT_OPTIONS[5]['text'], callback_data=PAYMENT_OPTIONS[5]['callback_data'])
|
||||||
|
]
|
||||||
])
|
])
|
||||||
|
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
@@ -72,6 +83,7 @@ async def process_callback_replenish_balance(callback_query: types.CallbackQuery
|
|||||||
await state.set_state(ReplenishBalanceState.choosing_amount)
|
await state.set_state(ReplenishBalanceState.choosing_amount)
|
||||||
await callback_query.answer()
|
await callback_query.answer()
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(lambda c: c.data == 'back_to_profile')
|
@router.callback_query(lambda c: c.data == 'back_to_profile')
|
||||||
async def back_to_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
|
async def back_to_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
|
||||||
await process_callback_view_profile(callback_query, state)
|
await process_callback_view_profile(callback_query, state)
|
||||||
@@ -126,9 +138,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
"currency": "RUB"
|
"currency": "RUB"
|
||||||
},
|
},
|
||||||
"vat_code": 6
|
"vat_code": 6
|
||||||
## Раскоментируйте следующие строки, если у вас регистрация как ИП, а не самозанятость
|
|
||||||
## "payment_subject": "payment",
|
|
||||||
## "payment_mode": "full_payment",
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -260,7 +269,9 @@ async def process_custom_amount_input(message: types.Message, state: FSMContext)
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await message.answer("Ошибка при создании платежа.")
|
await message.answer("Ошибка при создании платежа.")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.answer(f"Произошла ошибка при обработке платежа: {str(e)}")
|
logging.error(f"Ошибка при создании платежа: {e}")
|
||||||
|
await message.answer("Произошла ошибка при создании платежа.")
|
||||||
else:
|
else:
|
||||||
await message.answer("Некорректный ввод. Пожалуйста, введите сумму числом:")
|
await message.answer("Некорректная сумма. Пожалуйста, введите сумму еще раз:")
|
||||||
|
|||||||
+5
-4
@@ -5,7 +5,7 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
|||||||
|
|
||||||
from bot import bot
|
from bot import bot
|
||||||
from database import get_balance, get_key_count, get_referral_stats
|
from database import get_balance, get_key_count, get_referral_stats
|
||||||
from handlers.texts import profile_message_send, invite_message_send
|
from handlers.texts import profile_message_send, invite_message_send, CHANNEL_LINK, get_referral_link
|
||||||
|
|
||||||
|
|
||||||
class ReplenishBalanceState(StatesGroup):
|
class ReplenishBalanceState(StatesGroup):
|
||||||
@@ -13,6 +13,7 @@ class ReplenishBalanceState(StatesGroup):
|
|||||||
waiting_for_admin_confirmation = State()
|
waiting_for_admin_confirmation = State()
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
async def process_callback_view_profile(callback_query: types.CallbackQuery, state: FSMContext):
|
async def process_callback_view_profile(callback_query: types.CallbackQuery, state: FSMContext):
|
||||||
tg_id = callback_query.from_user.id
|
tg_id = callback_query.from_user.id
|
||||||
username = callback_query.from_user.full_name
|
username = callback_query.from_user.full_name
|
||||||
@@ -28,7 +29,7 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
|
|||||||
)
|
)
|
||||||
|
|
||||||
profile_message += (
|
profile_message += (
|
||||||
f"<b>Обязательно подпишитесь на канал</b> <a href='https://t.me/solonet_vpn'>здесь</a>\n"
|
f"<b>Обязательно подпишитесь на канал</b> <a href='{CHANNEL_LINK}'>здесь</a>\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
if key_count == 0:
|
if key_count == 0:
|
||||||
@@ -66,7 +67,7 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
|
|||||||
@router.callback_query(lambda c: c.data == 'invite')
|
@router.callback_query(lambda c: c.data == 'invite')
|
||||||
async def invite_handler(callback_query: types.CallbackQuery):
|
async def invite_handler(callback_query: types.CallbackQuery):
|
||||||
tg_id = callback_query.from_user.id
|
tg_id = callback_query.from_user.id
|
||||||
referral_link = f"https://t.me/SoloNetVPN_bot?start=referral_{tg_id}"
|
referral_link = get_referral_link(tg_id)
|
||||||
|
|
||||||
referral_stats = await get_referral_stats(tg_id)
|
referral_stats = await get_referral_stats(tg_id)
|
||||||
|
|
||||||
@@ -90,4 +91,4 @@ async def invite_handler(callback_query: types.CallbackQuery):
|
|||||||
|
|
||||||
@router.callback_query(lambda c: c.data == 'view_profile')
|
@router.callback_query(lambda c: c.data == 'view_profile')
|
||||||
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
|
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
|
||||||
await process_callback_view_profile(callback_query, state)
|
await process_callback_view_profile(callback_query, state)
|
||||||
|
|||||||
+1
-5
@@ -8,7 +8,7 @@ from handlers.texts import ABOUT_VPN, WELCOME_TEXT
|
|||||||
from bot import bot
|
from bot import bot
|
||||||
from config import CHANNEL_URL, SUPPORT_CHAT_URL
|
from config import CHANNEL_URL, SUPPORT_CHAT_URL
|
||||||
from database import add_connection, add_referral, check_connection_exists, get_trial
|
from database import add_connection, add_referral, check_connection_exists, get_trial
|
||||||
from handlers.trial_key import create_trial_key
|
from handlers.keys.trial_key import create_trial_key
|
||||||
from handlers.texts import INSTRUCTIONS_TRIAL
|
from handlers.texts import INSTRUCTIONS_TRIAL
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
@@ -65,23 +65,19 @@ async def handle_connect_vpn(callback_query: CallbackQuery):
|
|||||||
await callback_query.message.delete()
|
await callback_query.message.delete()
|
||||||
user_id = callback_query.from_user.id
|
user_id = callback_query.from_user.id
|
||||||
|
|
||||||
# Создаём триальный ключ
|
|
||||||
trial_key_info = await create_trial_key(user_id)
|
trial_key_info = await create_trial_key(user_id)
|
||||||
|
|
||||||
if 'error' in trial_key_info:
|
if 'error' in trial_key_info:
|
||||||
await callback_query.message.answer(trial_key_info['error'])
|
await callback_query.message.answer(trial_key_info['error'])
|
||||||
else:
|
else:
|
||||||
# Формируем сообщение с ключом и инструкциями
|
|
||||||
key_message = (
|
key_message = (
|
||||||
f"<b>Ваш ключ доступа:</b>\n<pre>{trial_key_info['key']}</pre>\n\n"
|
f"<b>Ваш ключ доступа:</b>\n<pre>{trial_key_info['key']}</pre>\n\n"
|
||||||
f"<b>Инструкции:</b>\n{INSTRUCTIONS_TRIAL}"
|
f"<b>Инструкции:</b>\n{INSTRUCTIONS_TRIAL}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Кнопка "В профиль"
|
|
||||||
button_profile = InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')
|
button_profile = InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')
|
||||||
inline_keyboard_profile = InlineKeyboardMarkup(inline_keyboard=[[button_profile]])
|
inline_keyboard_profile = InlineKeyboardMarkup(inline_keyboard=[[button_profile]])
|
||||||
|
|
||||||
# Отправляем текст с ключом и инструкциями в виде цитаты
|
|
||||||
await callback_query.message.answer(
|
await callback_query.message.answer(
|
||||||
key_message,
|
key_message,
|
||||||
parse_mode='HTML',
|
parse_mode='HTML',
|
||||||
|
|||||||
+30
-2
@@ -1,5 +1,29 @@
|
|||||||
from config import BOT_VERSION
|
BOT_VERSION = '1.3.2'
|
||||||
|
|
||||||
|
### Функции образования цен и кнопок продления ключа
|
||||||
|
PAYMENT_OPTIONS = [
|
||||||
|
{'text': '100 RUB', 'callback_data': 'amount_100'},
|
||||||
|
{'text': '300 RUB', 'callback_data': 'amount_300'},
|
||||||
|
{'text': '600 RUB', 'callback_data': 'amount_600'},
|
||||||
|
{'text': '1000 RUB', 'callback_data': 'amount_1000'},
|
||||||
|
{'text': '💰 Ввести свою сумму', 'callback_data': 'enter_custom_amount'},
|
||||||
|
{'text': '⬅️ Назад', 'callback_data': 'back_to_profile'},
|
||||||
|
]
|
||||||
|
|
||||||
|
RENEWAL_PLANS = {
|
||||||
|
'1': {'months': 1, 'price': 100},
|
||||||
|
'3': {'months': 3, 'price': 285},
|
||||||
|
'6': {'months': 6, 'price': 540},
|
||||||
|
'12': {'months': 12, 'price': 1000},
|
||||||
|
}
|
||||||
|
|
||||||
|
INSUFFICIENT_FUNDS_MSG = "Недостаточно средств для продления ключа."
|
||||||
|
KEY_NOT_FOUND_MSG = "Ключ не найден."
|
||||||
|
SUCCESS_RENEWAL_MSG = "Ваш ключ был успешно продлен на {months} месяц(-а)."
|
||||||
|
ERROR_RENEWAL_MSG = "Ошибка при продлении ключа."
|
||||||
|
PLAN_SELECTION_MSG = "<b>Выберите план продления:</b>\n\n💰 <b>Баланс:</b> {balance} руб.\n\n📅 <b>Текущая дата истечения ключа:</b> {expiry_date}"
|
||||||
|
|
||||||
|
### Текст главного меню
|
||||||
WELCOME_TEXT = (
|
WELCOME_TEXT = (
|
||||||
"<b>🎉 SoloNet — твой доступ в свободный интернет! 🌐✨</b>\n\n"
|
"<b>🎉 SoloNet — твой доступ в свободный интернет! 🌐✨</b>\n\n"
|
||||||
"<b>Наши преимущества:</b>\n"
|
"<b>Наши преимущества:</b>\n"
|
||||||
@@ -80,7 +104,6 @@ INSTRUCTIONS_TRIAL = (
|
|||||||
"💬 Если у вас возникнут вопросы, не стесняйтесь обращаться в <a href='https://t.me/solonet_sup'>поддержку</a>."
|
"💬 Если у вас возникнут вопросы, не стесняйтесь обращаться в <a href='https://t.me/solonet_sup'>поддержку</a>."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
KEY_EXPIRY_10H = "🔔 Уведомление: Ваш ключ {email} для сервера {server_id} истекает через 10 часов.\n" \
|
KEY_EXPIRY_10H = "🔔 Уведомление: Ваш ключ {email} для сервера {server_id} истекает через 10 часов.\n" \
|
||||||
"Дата истечения: {expiry_date}"\
|
"Дата истечения: {expiry_date}"\
|
||||||
"Перейдите в профиль и пополните баланс, всего 100 рублей на целый месяц"\
|
"Перейдите в профиль и пополните баланс, всего 100 рублей на целый месяц"\
|
||||||
@@ -96,6 +119,11 @@ KEY_RENEWAL_FAILED = "Не удалось продлить ключ на пан
|
|||||||
KEY_DELETED = "Ваш ключ был удален из-за недостаточного баланса."
|
KEY_DELETED = "Ваш ключ был удален из-за недостаточного баланса."
|
||||||
KEY_DELETION_FAILED = "Не удалось удалить ключ с панели, обратитесь в поддержку."
|
KEY_DELETION_FAILED = "Не удалось удалить ключ с панели, обратитесь в поддержку."
|
||||||
|
|
||||||
|
CHANNEL_LINK = "https://t.me/solonet_vpn"
|
||||||
|
|
||||||
|
def get_referral_link(user_id):
|
||||||
|
return f"https://t.me/SoloNetVPN_bot?start=referral_{user_id}"
|
||||||
|
|
||||||
def key_message_success(connection_link, remaining_time_message):
|
def key_message_success(connection_link, remaining_time_message):
|
||||||
key_message = (
|
key_message = (
|
||||||
"✅ Ключ успешно создан:\n"
|
"✅ Ключ успешно создан:\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user