Add dev mode and fix menu and fix stars and cryptobot

This commit is contained in:
Zakhar Izmaylov
2024-11-15 11:40:25 +03:00
parent deafbfb4ee
commit 2f10ae0b74
10 changed files with 117 additions and 100 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[flake8]
max-line-length = 250
ignore = E203, E266, E501, W503, F541, E704, W293, W291, E126, E121, E123, E128, E302, E131, E231, W292, E402, E261
ignore = E203, E266, E501, W503, F541, E704, W293, W291, E126, E121, E123, E128, E302, E131, E231, W292, E402, E261, E305
max-complexity = 25
select = B, C, E, F, W, T4, B9
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,.txt
+6
View File
@@ -28,10 +28,16 @@ async def handle_activate_coupon(
except Exception as e:
logger.error(f"Ошибка при удалении сообщения: {e}")
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="⬅️ Вернуться в профиль", callback_data="view_profile")
)
await callback_query.message.answer(
"<b>Введите код купона:</b>\n\n"
"Пожалуйста, введите действующий код купона, который вы хотите активировать.",
parse_mode="HTML",
reply_markup=builder.as_markup(),
)
await state.set_state(CouponActivationState.waiting_for_coupon_code)
await callback_query.answer()
View File
+3 -1
View File
@@ -18,7 +18,9 @@ async def send_instructions(callback_query: types.CallbackQuery):
await callback_query.answer()
return
back_button = InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_main")
back_button = InlineKeyboardButton(
text="⬅️ Вернуться в профиль", callback_data="view_profile"
)
keyboard = InlineKeyboardMarkup(inline_keyboard=[[back_button]])
with open(image_path, "rb") as image_from_buffer:
+31 -37
View File
@@ -10,7 +10,6 @@ from loguru import logger
from bot import bot
from config import CRYPTO_BOT_ENABLE, CRYPTO_BOT_TOKEN, RUB_TO_USDT
from database import add_connection, check_connection_exists, get_key_count, update_balance
from handlers.profile import process_callback_view_profile
from handlers.texts import PAYMENT_OPTIONS
router = Router()
@@ -20,9 +19,9 @@ if CRYPTO_BOT_ENABLE:
class ReplenishBalanceState(StatesGroup):
choosing_amount = State()
waiting_for_payment_confirmation = State()
entering_custom_amount = State()
choosing_amount_crypto = State()
waiting_for_payment_confirmation_crypto = State()
entering_custom_amount_crypto = State()
async def send_message_with_deletion(
@@ -63,23 +62,23 @@ async def process_callback_pay_cryptobot(
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
callback_data=f'crypto_{PAYMENT_OPTIONS[i]["callback_data"]}',
),
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i + 1]["text"],
callback_data=PAYMENT_OPTIONS[i + 1]["callback_data"],
callback_data=f'crypto_{PAYMENT_OPTIONS[i + 1]["callback_data"]}',
),
)
else:
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
callback_data=f'crypto_{PAYMENT_OPTIONS[i]["callback_data"]}',
)
)
builder.row(
InlineKeyboardButton(
text="💰 Ввести свою сумму", callback_data="enter_custom_amount"
text="💰 Ввести свою сумму", callback_data="enter_custom_amount_crypto"
)
)
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="back_to_profile"))
@@ -104,18 +103,11 @@ async def process_callback_pay_cryptobot(
reply_markup=builder.as_markup(),
)
await state.set_state(ReplenishBalanceState.choosing_amount)
await state.set_state(ReplenishBalanceState.choosing_amount_crypto)
await callback_query.answer()
@router.callback_query(F.data == "back_to_profile")
async def back_to_profile_handler(
callback_query: types.CallbackQuery, state: FSMContext
):
await process_callback_view_profile(callback_query, state)
@router.callback_query(F.data.startswith("amount|"))
@router.callback_query(F.data.startswith("crypto_amount|"))
async def process_amount_selection(
callback_query: types.CallbackQuery, state: FSMContext
):
@@ -143,24 +135,24 @@ async def process_amount_selection(
return
await state.update_data(amount=amount)
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation)
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_crypto)
try:
invoice = await crypto.create_invoice(
asset="USDT",
amount=str(amount // RUB_TO_USDT),
description=f"Пополнения баланса на {amount//RUB_TO_USDT} руб",
payload=f"{callback_query.from_user.id}:{amount//RUB_TO_USDT}",
amount=str(int(amount // RUB_TO_USDT)),
description=f"Пополнения баланса на {amount} руб",
payload=f"{callback_query.from_user.id}:{int(amount)}",
)
if hasattr(invoice, "bot_invoice_url"):
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="Пополнить", url=invoice.bot_invoice_url),
InlineKeyboardButton(text="⬅️ Назад", callback_data="back_to_profile"),
InlineKeyboardButton(text="Пополнить", url=invoice.bot_invoice_url)
)
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"))
await callback_query.message.edit_text(
text=f"Вы выбрали пополнение на {amount//RUB_TO_USDT} рублей.",
text=f"Вы выбрали пополнение на {amount} рублей.",
reply_markup=builder.as_markup(),
)
else:
@@ -211,7 +203,7 @@ async def process_crypto_payment(payload):
user_id_str, amount_str = custom_payload.split(":")
try:
user_id = int(user_id_str)
amount = float(amount_str)
amount = int(amount_str)
logger.debug(f"Payment succeeded for user_id: {user_id}, amount: {amount}")
await update_balance(user_id, amount)
await send_payment_success_notification(user_id, amount)
@@ -221,16 +213,16 @@ async def process_crypto_payment(payload):
logger.warning(f"Получен неоплаченный инвойс: {payload}")
@router.callback_query(F.data == "enter_custom_amount")
@router.callback_query(F.data == "enter_custom_amount_crypto")
async def process_enter_custom_amount(
callback_query: types.CallbackQuery, state: FSMContext
):
await callback_query.message.edit_text(text="Введите сумму пополнения:")
await state.set_state(ReplenishBalanceState.entering_custom_amount)
await state.set_state(ReplenishBalanceState.entering_custom_amount_crypto)
await callback_query.answer()
@router.message(State(ReplenishBalanceState.entering_custom_amount))
@router.message(State(ReplenishBalanceState.entering_custom_amount_crypto))
async def process_custom_amount_input(message: types.Message, state: FSMContext):
if message.text.isdigit():
amount = int(message.text)
@@ -241,25 +233,27 @@ async def process_custom_amount_input(message: types.Message, state: FSMContext)
return
await state.update_data(amount=amount)
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation)
await state.set_state(
ReplenishBalanceState.waiting_for_payment_confirmation_crypto
)
try:
invoice = await crypto.create_invoice(
asset="USDT",
amount=str(amount // RUB_TO_USDT),
description=f"Пополнения баланса на {amount//RUB_TO_USDT} руб",
payload=f"{message.from_user.id}:{amount//RUB_TO_USDT}",
amount=str(int(amount // RUB_TO_USDT)),
description=f"Пополнения баланса на {amount} руб",
payload=f"{message.from_user.id}:{amount}",
)
if hasattr(invoice, "bot_invoice_url"):
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="Пополнить", url=invoice.bot_invoice_url),
InlineKeyboardButton(
text="⬅️ Назад", callback_data="back_to_profile"
),
InlineKeyboardButton(text="Пополнить", url=invoice.bot_invoice_url)
)
builder.row(
InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"),
)
await message.message.edit_text(
text=f"Вы выбрали пополнение на {amount//RUB_TO_USDT} рублей.",
text=f"Вы выбрали пополнение на {amount} рублей.",
reply_markup=builder.as_markup(),
)
else:
+36 -33
View File
@@ -1,23 +1,22 @@
from aiogram import F, Router, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import InlineKeyboardButton, LabeledPrice
from aiogram.types import InlineKeyboardButton, LabeledPrice, PreCheckoutQuery
from aiogram.utils.keyboard import InlineKeyboardBuilder
from loguru import logger
from bot import bot
from config import RUB_TO_XTR
from database import add_connection, check_connection_exists, get_key_count, update_balance
from handlers.profile import process_callback_view_profile
from handlers.texts import PAYMENT_OPTIONS
router = Router()
class ReplenishBalanceState(StatesGroup):
choosing_amount = State()
waiting_for_payment_confirmation = State()
entering_custom_amount = State()
choosing_amount_stars = State()
waiting_for_payment_confirmation_stars = State()
entering_custom_amount_stars = State()
async def send_message_with_deletion(
@@ -58,26 +57,26 @@ async def process_callback_pay_stars(
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
callback_data=f'stars_{PAYMENT_OPTIONS[i]["callback_data"]}',
),
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i + 1]["text"],
callback_data=PAYMENT_OPTIONS[i + 1]["callback_data"],
callback_data=f'stars_{PAYMENT_OPTIONS[i + 1]["callback_data"]}',
),
)
else:
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
callback_data=f'stars_{PAYMENT_OPTIONS[i]["callback_data"]}',
)
)
builder.row(
InlineKeyboardButton(
text="💰 Ввести свою сумму", callback_data="enter_custom_amount"
text="💰 Ввести свою сумму", callback_data="enter_custom_amount_stars"
)
)
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="back_to_profile"))
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"))
key_count = await get_key_count(tg_id)
@@ -99,18 +98,11 @@ async def process_callback_pay_stars(
reply_markup=builder.as_markup(),
)
await state.set_state(ReplenishBalanceState.choosing_amount)
await state.set_state(ReplenishBalanceState.choosing_amount_stars)
await callback_query.answer()
@router.callback_query(F.data == "back_to_profile")
async def back_to_profile_handler(
callback_query: types.CallbackQuery, state: FSMContext
):
await process_callback_view_profile(callback_query, state)
@router.callback_query(F.data.startswith("amount|"))
@router.callback_query(F.data.startswith("starts_amount|"))
async def process_amount_selection(
callback_query: types.CallbackQuery, state: FSMContext
):
@@ -138,18 +130,20 @@ async def process_amount_selection(
return
await state.update_data(amount=amount)
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation)
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_stars)
try:
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="Пополнить", pay=True),
InlineKeyboardButton(text="⬅️ Назад", callback_data="back_to_profile"),
)
builder.row(
InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"),
)
await callback_query.message.answer_invoice(
title=f"Вы выбрали пополнение на {amount//RUB_TO_XTR} рублей.",
description=f"Вы выбрали пополнение на {amount//RUB_TO_XTR} рублей.",
prices=[LabeledPrice(label="XTR", amount=amount)],
title=f"Вы выбрали пополнение на {amount} рублей.",
description=f"Вы выбрали пополнение на {amount} рублей.",
prices=[LabeledPrice(label="XTR", amount=int(amount // RUB_TO_XTR))],
provider_token="",
payload=f"{amount}_stars",
currency="XTR",
@@ -176,16 +170,16 @@ async def send_payment_success_notification(user_id: int, amount: float):
logger.error(f"Ошибка при отправке уведомления пользователю {user_id}: {e}")
@router.callback_query(F.data == "enter_custom_amount")
@router.callback_query(F.data == "enter_custom_amount_stars")
async def process_enter_custom_amount(
callback_query: types.CallbackQuery, state: FSMContext
):
await callback_query.message.edit_text(text="Введите сумму пополнения:")
await state.set_state(ReplenishBalanceState.entering_custom_amount)
await state.set_state(ReplenishBalanceState.entering_custom_amount_stars)
await callback_query.answer()
@router.message(State(ReplenishBalanceState.entering_custom_amount))
@router.message(ReplenishBalanceState.entering_custom_amount_stars)
async def process_custom_amount_input(message: types.Message, state: FSMContext):
if message.text.isdigit():
amount = int(message.text)
@@ -196,17 +190,21 @@ async def process_custom_amount_input(message: types.Message, state: FSMContext)
return
await state.update_data(amount=amount)
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation)
await state.set_state(
ReplenishBalanceState.waiting_for_payment_confirmation_stars
)
try:
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="Пополнить", pay=True),
InlineKeyboardButton(text="⬅️ Назад", callback_data="back_to_profile"),
)
builder.row(
InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"),
)
await message.answer_invoice(
title=f"Вы выбрали пополнение на {amount//RUB_TO_XTR} рублей.",
description=f"Вы выбрали пополнение на {amount//RUB_TO_XTR} рублей.",
prices=[LabeledPrice(label="XTR", amount=amount)],
title=f"Вы выбрали пополнение на {amount} рублей.",
description=f"Вы выбрали пополнение на {amount} рублей.",
prices=[LabeledPrice(label="XTR", amount=int(amount // RUB_TO_XTR))],
provider_token="",
payload=f"{amount}_stars",
currency="XTR",
@@ -219,13 +217,18 @@ async def process_custom_amount_input(message: types.Message, state: FSMContext)
await message.answer("Некорректная сумма. Пожалуйста, введите сумму еще раз:")
@router.pre_checkout_query()
async def on_pre_checkout_query(pre_checkout_query: PreCheckoutQuery):
await pre_checkout_query.answer(ok=True)
@router.message(F.successful_payment)
async def on_successful_payment(
message: types.Message,
):
try:
user_id = int(message.from_user.id)
amount = float(message.successful_payment.total_amount)
amount = float(message.successful_payment.invoice_payload.split("_")[0])
logger.debug(f"Payment succeeded for user_id: {user_id}, amount: {amount}")
await update_balance(user_id, amount)
await send_payment_success_notification(user_id, amount)
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+1
View File
@@ -136,4 +136,5 @@ async def invite_handler(callback_query: types.CallbackQuery):
@router.callback_query(F.data == "view_profile")
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
await state.clear()
await process_callback_view_profile(callback_query, state)
+2
View File
@@ -28,6 +28,8 @@ async def send_welcome_message(chat_id: int, trial_status: int):
)
builder.row(
InlineKeyboardButton(text="📞 Техническая поддержка", url=SUPPORT_CHAT_URL),
)
builder.row(
InlineKeyboardButton(text="📢 Официальный канал", url=CHANNEL_URL),
)
builder.row(InlineKeyboardButton(text="🌐 О нашем VPN", callback_data="about_vpn"))
+37 -28
View File
@@ -7,7 +7,7 @@ from loguru import logger
from backup import backup_database
from bot import bot, dp, router
from config import CRYPTO_BOT_ENABLE, FREEKASSA_ENABLE, SUB_PATH, WEBAPP_HOST, WEBAPP_PORT, WEBHOOK_PATH, WEBHOOK_URL, YOOKASSA_ENABLE
from config import CRYPTO_BOT_ENABLE, DEV_MODE, FREEKASSA_ENABLE, SUB_PATH, WEBAPP_HOST, WEBAPP_PORT, WEBHOOK_PATH, WEBHOOK_URL, YOOKASSA_ENABLE
from database import init_db
from handlers.keys.subscriptions import handle_subscription
from handlers.notifications import notify_expiring_keys
@@ -54,38 +54,47 @@ async def shutdown_site(site):
async def main():
dp.include_router(router)
app = web.Application()
app.on_startup.append(on_startup)
app.on_shutdown.append(on_shutdown)
if YOOKASSA_ENABLE:
app.router.add_post("/yookassa/webhook", yookassa_webhook)
if FREEKASSA_ENABLE:
app.router.add_post("/freekassa/webhook", freekassa_webhook)
if CRYPTO_BOT_ENABLE:
app.router.add_post("/cryptobot/webhook", cryptobot_webhook)
app.router.add_get(f"{SUB_PATH}{{email}}", handle_subscription)
if DEV_MODE:
# Запуск в режиме полинга для разработки
await bot.delete_webhook()
await init_db()
await dp.start_polling(bot)
else:
# Стандартный режим вебхука
app = web.Application()
app.on_startup.append(on_startup)
app.on_shutdown.append(on_shutdown)
if YOOKASSA_ENABLE:
app.router.add_post("/yookassa/webhook", yookassa_webhook)
if FREEKASSA_ENABLE:
app.router.add_post("/freekassa/webhook", freekassa_webhook)
if CRYPTO_BOT_ENABLE:
app.router.add_post("/cryptobot/webhook", cryptobot_webhook)
app.router.add_get(f"{SUB_PATH}{{email}}", handle_subscription)
SimpleRequestHandler(dispatcher=dp, bot=bot).register(app, path=WEBHOOK_PATH)
setup_application(app, dp, bot=bot)
SimpleRequestHandler(dispatcher=dp, bot=bot).register(app, path=WEBHOOK_PATH)
setup_application(app, dp, bot=bot)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, host=WEBAPP_HOST, port=WEBAPP_PORT)
await site.start()
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, host=WEBAPP_HOST, port=WEBAPP_PORT)
await site.start()
logger.info(f"Webhook URL: {WEBHOOK_URL}")
logger.info(f"Webhook URL: {WEBHOOK_URL}")
loop = asyncio.get_event_loop()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, lambda: asyncio.create_task(shutdown_site(site)))
loop = asyncio.get_event_loop()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(
sig, lambda: asyncio.create_task(shutdown_site(site))
)
try:
await asyncio.Event().wait()
finally:
pending = asyncio.all_tasks()
for task in pending:
task.cancel()
await asyncio.gather(*pending, return_exceptions=True)
try:
await asyncio.Event().wait()
finally:
pending = asyncio.all_tasks()
for task in pending:
task.cancel()
await asyncio.gather(*pending, return_exceptions=True)
if __name__ == "__main__":