fiatCryptobot/flowPayments/Buttons/fixNotify/BanOfUsers/fixTrial and more
This commit is contained in:
+13
-1
@@ -99,4 +99,16 @@ CREATE TABLE IF NOT EXISTS gifts
|
||||
recipient_tg_id BIGINT,
|
||||
CONSTRAINT fk_sender FOREIGN KEY (sender_tg_id) REFERENCES users (tg_id),
|
||||
CONSTRAINT fk_recipient FOREIGN KEY (recipient_tg_id) REFERENCES users (tg_id)
|
||||
);
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS temporary_data (
|
||||
tg_id BIGINT PRIMARY KEY NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
data JSONB NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS blocked_users (
|
||||
tg_id BIGINT PRIMARY KEY,
|
||||
blocked_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
+40
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
@@ -7,6 +8,45 @@ from config import DATABASE_URL, REFERRAL_BONUS_PERCENTAGES
|
||||
from logger import logger
|
||||
|
||||
|
||||
async def save_temporary_data(session, tg_id: int, state: str, data: dict):
|
||||
"""Сохраняет временные данные пользователя."""
|
||||
await session.execute(
|
||||
"""
|
||||
INSERT INTO temporary_data (tg_id, state, data, updated_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (tg_id)
|
||||
DO UPDATE SET state = $2, data = $3, updated_at = $4
|
||||
""",
|
||||
tg_id, state, json.dumps(data), datetime.utcnow()
|
||||
)
|
||||
|
||||
async def get_temporary_data(session, tg_id: int) -> dict | None:
|
||||
"""Извлекает временные данные пользователя."""
|
||||
result = await session.fetchrow(
|
||||
"SELECT state, data FROM temporary_data WHERE tg_id = $1",
|
||||
tg_id
|
||||
)
|
||||
if result:
|
||||
return {
|
||||
"state": result["state"],
|
||||
"data": json.loads(result["data"])
|
||||
}
|
||||
return None
|
||||
|
||||
async def clear_temporary_data(session, tg_id: int):
|
||||
await session.execute(
|
||||
"DELETE FROM temporary_data WHERE tg_id = $1",
|
||||
tg_id
|
||||
)
|
||||
|
||||
async def add_blocked_user(tg_id: int, conn: asyncpg.Connection):
|
||||
await conn.execute(
|
||||
"INSERT INTO blocked_users (tg_id) VALUES ($1) ON CONFLICT (tg_id) DO NOTHING",
|
||||
tg_id
|
||||
)
|
||||
|
||||
|
||||
|
||||
async def init_db(file_path: str = "assets/schema.sql"):
|
||||
with open(file_path) as file:
|
||||
sql_content = file.read()
|
||||
|
||||
@@ -3,6 +3,7 @@ from datetime import datetime
|
||||
from io import BytesIO
|
||||
from typing import Any
|
||||
|
||||
import asyncpg
|
||||
from aiogram import F, Router, types
|
||||
from aiogram.filters import Command
|
||||
from aiogram.fsm.context import FSMContext
|
||||
@@ -12,6 +13,7 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from backup import backup_database
|
||||
from bot import bot
|
||||
from config import DATABASE_URL
|
||||
from filters.admin import IsAdminFilter
|
||||
from logger import logger
|
||||
|
||||
@@ -34,7 +36,7 @@ async def handle_admin_callback_query(callback_query: CallbackQuery, state: FSMC
|
||||
async def handle_admin_message(message: types.Message, state: FSMContext):
|
||||
await state.clear()
|
||||
|
||||
BOT_VERSION = "3.2.5-beta" # Укажите текущую версию бота
|
||||
BOT_VERSION = "4.0.0-preAlpha" # Укажите текущую версию бота
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
@@ -84,6 +86,9 @@ async def handle_bot_management(callback_query: types.CallbackQuery):
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🔄 Перезагрузить бота", callback_data="restart_bot")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🚫 Баны", callback_data="ban_user")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="⬅️ Назад", callback_data="admin")
|
||||
)
|
||||
@@ -93,6 +98,7 @@ async def handle_bot_management(callback_query: types.CallbackQuery):
|
||||
)
|
||||
|
||||
|
||||
|
||||
@router.callback_query(F.data == "user_stats", IsAdminFilter())
|
||||
async def user_stats_menu(callback_query: CallbackQuery, session: Any):
|
||||
try:
|
||||
@@ -434,3 +440,94 @@ async def user_editor_menu(callback_query: CallbackQuery):
|
||||
await callback_query.message.answer(
|
||||
"👇 Выберите способ поиска пользователя:", reply_markup=builder.as_markup()
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "ban_user")
|
||||
async def handle_ban_user(callback_query: types.CallbackQuery):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="📄 Выгрузить в CSV", callback_data="export_to_csv")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🗑️ Удалить из БД", callback_data="delete_banned_users")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="⬅️ Назад", callback_data="bot_management")
|
||||
)
|
||||
await callback_query.message.answer(
|
||||
"🚫 Заблокировавшие бота\n\n"
|
||||
"Здесь можно просматривать и удалять пользователей, которые забанили вашего бота!",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "export_to_csv")
|
||||
async def export_banned_users_to_csv(callback_query: types.CallbackQuery):
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
banned_users = await conn.fetch("SELECT tg_id, blocked_at FROM blocked_users")
|
||||
|
||||
import csv
|
||||
import io
|
||||
csv_output = io.StringIO()
|
||||
writer = csv.writer(csv_output)
|
||||
writer.writerow(["tg_id", "blocked_at"])
|
||||
for user in banned_users:
|
||||
writer.writerow([user["tg_id"], user["blocked_at"]])
|
||||
|
||||
csv_output.seek(0)
|
||||
|
||||
document = BufferedInputFile(
|
||||
file=csv_output.getvalue().encode("utf-8"),
|
||||
filename="banned_users.csv"
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="⬅️ Назад", callback_data="bot_management")
|
||||
)
|
||||
|
||||
await callback_query.message.answer_document(
|
||||
document=document,
|
||||
caption="📄 Список заблокировавших бота пользователей",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
except Exception as e:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="⬅️ Назад", callback_data="bot_management")
|
||||
)
|
||||
await callback_query.message.answer(
|
||||
text=f"Ошибка при выгрузке CSV: {e}",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "delete_banned_users")
|
||||
async def delete_banned_users(callback_query: types.CallbackQuery):
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
deleted_count = await conn.execute("DELETE FROM blocked_users")
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="⬅️ Назад", callback_data="bot_management")
|
||||
)
|
||||
|
||||
await callback_query.message.answer(
|
||||
text=f"🗑️ Удалено {deleted_count} записей о заблокировавших пользователях.",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
except Exception as e:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="⬅️ Назад", callback_data="bot_management")
|
||||
)
|
||||
await callback_query.message.answer(
|
||||
text=f"Ошибка при удалении записей: {e}",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
@@ -56,7 +56,6 @@ async def prompt_username(callback_query: CallbackQuery, state: FSMContext):
|
||||
async def handle_username_input(
|
||||
message: types.Message, state: FSMContext, session: Any
|
||||
):
|
||||
# Extract the username from a message text by removing leading '@' and the Telegram URL prefix
|
||||
username = message.text.strip().lstrip('@').replace('https://t.me/', '')
|
||||
user_record = await session.fetchrow(
|
||||
"SELECT tg_id FROM users WHERE username = $1", username
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
DOWNLOAD_IOS_BUTTON = "🍏 Скачать для iOS"
|
||||
DOWNLOAD_ANDROID_BUTTON = "🤖 Скачать для Android"
|
||||
IMPORT_IOS = "🍏 Подключить на iOS"
|
||||
IMPORT_ANDROID = "🤖 Подключить на Android"
|
||||
PC_BUTTON = "💻 Компьютеры"
|
||||
TV_BUTTON = "📺 Андроид TV"
|
||||
@@ -0,0 +1,3 @@
|
||||
RENEW_KEY = "🔄 Продлить подписку"
|
||||
ADD_KEY = "➕ Добавить подписку"
|
||||
PROFILE = "👤 Личный кабинет"
|
||||
@@ -1,5 +1,5 @@
|
||||
ADD_SUB = "➕ Устройство"
|
||||
MY_SUBS = "📱 Мои устройства"
|
||||
ADD_SUB = "➕ Подписка"
|
||||
MY_SUBS = "📱 Мои подписки"
|
||||
PAYMENT = "💳 Пополнить баланс"
|
||||
INVITE = "👥 Пригласить"
|
||||
GIFTS = "🎁 Подарить"
|
||||
|
||||
@@ -8,6 +8,7 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from config import CONNECT_MACOS, CONNECT_WINDOWS, DATABASE_URL, SUPPORT_CHAT_URL
|
||||
from handlers.texts import CONNECT_TV_TEXT, INSTRUCTION_PC, INSTRUCTIONS, KEY_MESSAGE, SUBSCRIPTION_DETAILS_TEXT
|
||||
from logger import logger
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -117,7 +118,7 @@ async def process_continue_tv(callback_query: types.CallbackQuery):
|
||||
key_name = callback_query.data.split("|")[1]
|
||||
tg_id = callback_query.from_user.id
|
||||
|
||||
print(f"tg_id: {tg_id}, key_name: {key_name}") # Отладочный вывод
|
||||
logger.info(f"tg_id: {tg_id}, key_name: {key_name}")
|
||||
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
@@ -131,7 +132,7 @@ async def process_continue_tv(callback_query: types.CallbackQuery):
|
||||
key_name,
|
||||
)
|
||||
|
||||
print(f"Query result: {record}") # Отладочный вывод результата
|
||||
logger.info(f"Query result: {record}")
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from bot import bot
|
||||
from config import (
|
||||
CONNECT_ANDROID,
|
||||
CONNECT_IOS,
|
||||
@@ -18,9 +19,19 @@ from config import (
|
||||
RENEWAL_PRICES,
|
||||
SUPPORT_CHAT_URL,
|
||||
TRIAL_TIME,
|
||||
USE_NEW_PAYMENT_FLOW,
|
||||
)
|
||||
from database import get_balance, get_trial, save_temporary_data, store_key, update_balance
|
||||
from handlers.buttons.add_subscribe import (
|
||||
DOWNLOAD_ANDROID_BUTTON,
|
||||
DOWNLOAD_IOS_BUTTON,
|
||||
IMPORT_ANDROID,
|
||||
IMPORT_IOS,
|
||||
PC_BUTTON,
|
||||
TV_BUTTON,
|
||||
)
|
||||
from database import get_balance, get_trial, store_key, update_balance
|
||||
from handlers.keys.key_utils import create_key_on_cluster
|
||||
from handlers.payments.yookassa_pay import process_custom_amount_input
|
||||
from handlers.texts import DISCOUNTS, key_message_success
|
||||
from handlers.utils import generate_random_email, get_least_loaded_cluster
|
||||
from logger import logger
|
||||
@@ -88,7 +99,7 @@ async def handle_key_creation(
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("select_plan_"))
|
||||
async def select_tariff_plan(callback_query: CallbackQuery, state: FSMContext, session: Any):
|
||||
async def select_tariff_plan(callback_query: CallbackQuery, session: Any):
|
||||
tg_id = callback_query.message.chat.id
|
||||
plan_id = callback_query.data.split("_")[-1]
|
||||
plan_price = RENEWAL_PRICES.get(plan_id)
|
||||
@@ -98,28 +109,46 @@ async def select_tariff_plan(callback_query: CallbackQuery, state: FSMContext, s
|
||||
return
|
||||
|
||||
duration_days = int(plan_id) * 30
|
||||
|
||||
balance = await get_balance(tg_id)
|
||||
|
||||
await save_temporary_data(
|
||||
session,
|
||||
tg_id,
|
||||
"waiting_for_payment",
|
||||
{
|
||||
"plan_id": plan_id,
|
||||
"plan_price": plan_price,
|
||||
"duration_days": duration_days,
|
||||
"required_amount": max(0, plan_price - balance),
|
||||
}
|
||||
)
|
||||
|
||||
if balance < plan_price:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="💳 Пополнить баланс", callback_data="pay"))
|
||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||
await callback_query.message.answer(
|
||||
"💳 Недостаточно средств для создания подписки. Пополните баланс в личном кабинете.",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
await state.clear()
|
||||
required_amount = plan_price - balance
|
||||
|
||||
if USE_NEW_PAYMENT_FLOW:
|
||||
await process_custom_amount_input(callback_query, session)
|
||||
else:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="💳 Пополнить баланс", callback_data="pay"))
|
||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||
|
||||
await callback_query.message.answer(
|
||||
f"💳 Недостаточно средств. Для продолжения необходимо пополнить баланс на {required_amount}₽.",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
return
|
||||
|
||||
await update_balance(tg_id, -plan_price)
|
||||
|
||||
expiry_time = datetime.utcnow() + timedelta(days=duration_days)
|
||||
|
||||
await create_key(tg_id, expiry_time, state, session, callback_query)
|
||||
|
||||
await create_key(tg_id, expiry_time, None, session, callback_query)
|
||||
|
||||
async def create_key(
|
||||
tg_id: int, expiry_time: datetime, state: FSMContext, session: Any, message_or_query: Message | CallbackQuery
|
||||
tg_id: int,
|
||||
expiry_time: datetime,
|
||||
state: FSMContext | None,
|
||||
session: Any,
|
||||
message_or_query: Message | CallbackQuery | None = None,
|
||||
):
|
||||
"""Создаёт ключ с заданным сроком действия."""
|
||||
while True:
|
||||
@@ -169,19 +198,27 @@ async def create_key(
|
||||
await message_or_query.message.answer(
|
||||
"❌ Произошла ошибка при создании ключа. Пожалуйста, попробуйте снова."
|
||||
)
|
||||
else:
|
||||
await bot.send_message(
|
||||
chat_id=tg_id,
|
||||
text="❌ Произошла ошибка при создании ключа. Пожалуйста, попробуйте снова."
|
||||
)
|
||||
return
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="💬 Поддержка", url=SUPPORT_CHAT_URL))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🍏 Скачать для iOS", url=DOWNLOAD_IOS),
|
||||
InlineKeyboardButton(text="🤖 Скачать для Android", url=DOWNLOAD_ANDROID),
|
||||
InlineKeyboardButton(text=DOWNLOAD_IOS_BUTTON, url=DOWNLOAD_IOS),
|
||||
InlineKeyboardButton(text=DOWNLOAD_ANDROID_BUTTON, url=DOWNLOAD_ANDROID),
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🍏 Подключить на iOS", url=f"{CONNECT_IOS}{public_link}"),
|
||||
InlineKeyboardButton(text="🤖 Подключить на Android", url=f"{CONNECT_ANDROID}{public_link}"),
|
||||
InlineKeyboardButton(text=IMPORT_IOS, url=f"{CONNECT_IOS}{public_link}"),
|
||||
InlineKeyboardButton(text=IMPORT_ANDROID, url=f"{CONNECT_ANDROID}{public_link}"),
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="💻 Windows/Linux/MacOS", callback_data=f"connect_pc|{email}"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=PC_BUTTON, callback_data=f"connect_pc|{email}"),
|
||||
InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{email}"),
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||
|
||||
remaining_time = expiry_time - datetime.utcnow()
|
||||
@@ -192,5 +229,8 @@ async def create_key(
|
||||
await message_or_query.answer(key_message, reply_markup=builder.as_markup())
|
||||
elif isinstance(message_or_query, CallbackQuery):
|
||||
await message_or_query.message.answer(key_message, reply_markup=builder.as_markup())
|
||||
else:
|
||||
await bot.send_message(chat_id=tg_id, text=key_message, reply_markup=builder.as_markup())
|
||||
|
||||
await state.clear()
|
||||
if state:
|
||||
await state.clear()
|
||||
|
||||
+29
-38
@@ -25,6 +25,14 @@ from database import (
|
||||
update_balance,
|
||||
update_key_expiry,
|
||||
)
|
||||
from handlers.buttons.add_subscribe import (
|
||||
DOWNLOAD_ANDROID_BUTTON,
|
||||
DOWNLOAD_IOS_BUTTON,
|
||||
IMPORT_ANDROID,
|
||||
IMPORT_IOS,
|
||||
PC_BUTTON,
|
||||
TV_BUTTON,
|
||||
)
|
||||
from handlers.keys.key_utils import (
|
||||
delete_key_from_cluster,
|
||||
delete_key_from_db,
|
||||
@@ -69,10 +77,7 @@ async def process_callback_or_message_view_keys(
|
||||
chat_id,
|
||||
)
|
||||
|
||||
if records:
|
||||
inline_keyboard, response_message = build_keys_response(records)
|
||||
else:
|
||||
inline_keyboard, response_message = build_no_keys_response()
|
||||
inline_keyboard, response_message = build_keys_response(records)
|
||||
|
||||
image_path = os.path.join("img", "pic_keys.jpg")
|
||||
await send_with_optional_image(
|
||||
@@ -85,47 +90,33 @@ async def process_callback_or_message_view_keys(
|
||||
|
||||
def build_keys_response(records):
|
||||
"""
|
||||
Формирует сообщение и клавиатуру, если у пользователя есть устройства.
|
||||
Формирует сообщение и клавиатуру для устройств.
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
for record in records:
|
||||
key_name = record["email"]
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=f"🔑 {key_name}", callback_data=f"view_key|{key_name}"
|
||||
|
||||
if records:
|
||||
for record in records:
|
||||
key_name = record["email"]
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=f"🔑 {key_name}", callback_data=f"view_key|{key_name}"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile")
|
||||
)
|
||||
|
||||
inline_keyboard = builder.as_markup()
|
||||
response_message = (
|
||||
"<b>🔑 Список ваших устройств</b>\n\n"
|
||||
"<i>👇 Выберите устройство для управления подпиской:</i>"
|
||||
)
|
||||
return inline_keyboard, response_message
|
||||
|
||||
|
||||
def build_no_keys_response():
|
||||
"""
|
||||
Формирует сообщение и клавиатуру, если у пользователя нет устройств.
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="➕ Создать подписку", callback_data="create_key"
|
||||
text="➕ Добавить подписку", callback_data="create_key"
|
||||
)
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile")
|
||||
)
|
||||
|
||||
inline_keyboard = builder.as_markup()
|
||||
response_message = (
|
||||
"<b>❌ У вас пока нет активных устройств</b>\n\n"
|
||||
"<i>Нажмите кнопку ниже, чтобы создать устройство:</i>"
|
||||
"<b>🔑 Список ваших подписок</b>\n\n"
|
||||
"<i>👇 Выберите подписку для управления или добавьте новую (например, для подключения нового устройства):</i>"
|
||||
)
|
||||
return inline_keyboard, response_message
|
||||
|
||||
@@ -198,27 +189,27 @@ async def process_callback_view_key(callback_query: types.CallbackQuery, session
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🍏 Скачать для iOS", url=DOWNLOAD_IOS),
|
||||
InlineKeyboardButton(text=DOWNLOAD_IOS_BUTTON, url=DOWNLOAD_IOS),
|
||||
InlineKeyboardButton(
|
||||
text="🤖 Скачать для Android", url=DOWNLOAD_ANDROID
|
||||
text=DOWNLOAD_ANDROID_BUTTON, url=DOWNLOAD_ANDROID
|
||||
),
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="🍏 Подключить на iOS", url=f"{CONNECT_IOS}{key}"
|
||||
text=IMPORT_IOS, url=f"{CONNECT_IOS}{key}"
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text="🤖 Подключить на Android", url=f"{CONNECT_ANDROID}{key}"
|
||||
text=IMPORT_ANDROID, url=f"{CONNECT_ANDROID}{key}"
|
||||
),
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="💻 Компьютеры", callback_data=f"connect_pc|{key_name}"
|
||||
text=PC_BUTTON, callback_data=f"connect_pc|{key_name}"
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text="📺 Андроид TV", callback_data=f"connect_tv|{key_name}"
|
||||
text=TV_BUTTON, callback_data=f"connect_tv|{key_name}"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -229,7 +220,7 @@ async def process_callback_view_key(callback_query: types.CallbackQuery, session
|
||||
InlineKeyboardButton(
|
||||
text="❌ Удалить", callback_data=f"delete_key|{key_name}"
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile")
|
||||
|
||||
@@ -3,19 +3,19 @@ import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any
|
||||
|
||||
from config import ADMIN_PASSWORD, ADMIN_USERNAME, PUBLIC_LINK, TOTAL_GB, TRIAL_TIME
|
||||
from handlers.texts import INSTRUCTIONS
|
||||
import pytz
|
||||
from py3xui import AsyncApi
|
||||
|
||||
from client import add_client
|
||||
from config import ADMIN_PASSWORD, ADMIN_USERNAME, LIMIT_IP, PUBLIC_LINK, TOTAL_GB, TRIAL_TIME
|
||||
from database import get_servers_from_db, store_key, use_trial
|
||||
from handlers.texts import INSTRUCTIONS
|
||||
from handlers.utils import generate_random_email, get_least_loaded_cluster
|
||||
from logger import logger
|
||||
|
||||
|
||||
async def create_trial_key(tg_id: int, session: Any):
|
||||
try:
|
||||
# Проверка статуса триала
|
||||
trial_status = await session.fetchval(
|
||||
"SELECT trial FROM connections WHERE tg_id = $1",
|
||||
tg_id
|
||||
@@ -32,7 +32,9 @@ async def create_trial_key(tg_id: int, session: Any):
|
||||
public_link = f"{PUBLIC_LINK}{email}/{tg_id}"
|
||||
instructions = INSTRUCTIONS
|
||||
result = {"key": public_link, "instructions": instructions, "email": email}
|
||||
current_time = datetime.utcnow()
|
||||
|
||||
moscow_tz = pytz.timezone("Europe/Moscow")
|
||||
current_time = datetime.now(moscow_tz)
|
||||
expiry_time = current_time + timedelta(days=TRIAL_TIME)
|
||||
expiry_timestamp = int(expiry_time.timestamp() * 1000)
|
||||
|
||||
@@ -56,7 +58,7 @@ async def create_trial_key(tg_id: int, session: Any):
|
||||
client_id,
|
||||
email,
|
||||
tg_id,
|
||||
limit_ip=1,
|
||||
limit_ip=LIMIT_IP,
|
||||
total_gb=TOTAL_GB,
|
||||
expiry_time=expiry_timestamp,
|
||||
enable=True,
|
||||
|
||||
+165
-66
@@ -3,6 +3,7 @@ from datetime import datetime, timedelta
|
||||
|
||||
import asyncpg
|
||||
from aiogram import Bot, Router, types
|
||||
from aiogram.exceptions import TelegramForbiddenError
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from py3xui import AsyncApi
|
||||
|
||||
@@ -16,6 +17,7 @@ from config import (
|
||||
TRIAL_TIME,
|
||||
)
|
||||
from database import (
|
||||
add_blocked_user,
|
||||
add_notification,
|
||||
check_notification_time,
|
||||
delete_key,
|
||||
@@ -93,13 +95,14 @@ async def notify_10h_keys(
|
||||
"""
|
||||
SELECT tg_id, email, expiry_time, client_id, server_id FROM keys
|
||||
WHERE expiry_time <= $1 AND expiry_time > $2 AND notified = FALSE
|
||||
""",
|
||||
""",
|
||||
threshold_time_10h,
|
||||
current_time,
|
||||
)
|
||||
|
||||
logger.info(f"Найдено {len(records)} ключей для уведомления за 10 часов.")
|
||||
for record in records:
|
||||
|
||||
async def process_record(record):
|
||||
tg_id = record["tg_id"]
|
||||
email = record["email"]
|
||||
expiry_time = record["expiry_time"]
|
||||
@@ -123,7 +126,54 @@ async def notify_10h_keys(
|
||||
price=RENEWAL_PLANS["1"]["price"],
|
||||
)
|
||||
|
||||
if not await is_bot_blocked(bot, tg_id) and not DEV_MODE:
|
||||
balance = await get_balance(tg_id)
|
||||
|
||||
if balance >= RENEWAL_PLANS["1"]["price"]:
|
||||
try:
|
||||
await update_balance(tg_id, -RENEWAL_PLANS["1"]["price"])
|
||||
new_expiry_time = int(
|
||||
(datetime.utcnow() + timedelta(days=30)).timestamp() * 1000
|
||||
)
|
||||
await update_key_expiry(record["client_id"], new_expiry_time)
|
||||
|
||||
servers = await get_servers_from_db()
|
||||
|
||||
for cluster_id in servers:
|
||||
await renew_key_in_cluster(
|
||||
cluster_id, email, record["client_id"], new_expiry_time, TOTAL_GB
|
||||
)
|
||||
logger.info(
|
||||
f"Ключ для пользователя {tg_id} успешно продлен в кластере {cluster_id}."
|
||||
)
|
||||
|
||||
await conn.execute(
|
||||
"""
|
||||
UPDATE keys
|
||||
SET notified = FALSE, notified_24h = FALSE
|
||||
WHERE client_id = $1
|
||||
""",
|
||||
record["client_id"],
|
||||
)
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text="👤 Личный кабинет", callback_data="profile"
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
await bot.send_message(tg_id, text=KEY_RENEWED, reply_markup=keyboard)
|
||||
logger.info(
|
||||
f"Уведомление об успешном продлении отправлено клиенту {tg_id}."
|
||||
)
|
||||
except TelegramForbiddenError:
|
||||
logger.warning(f"Бот заблокирован пользователем {tg_id}. Записываем в blocked_users.")
|
||||
await add_blocked_user(tg_id, conn)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при продлении подписки для клиента {tg_id}: {e}")
|
||||
else:
|
||||
try:
|
||||
keyboard = InlineKeyboardBuilder()
|
||||
keyboard.button(
|
||||
@@ -132,22 +182,26 @@ async def notify_10h_keys(
|
||||
keyboard.button(text="💳 Пополнить баланс", callback_data="pay")
|
||||
keyboard.button(text="👤 Личный кабинет", callback_data="profile")
|
||||
keyboard.adjust(1)
|
||||
keyboard = keyboard.as_markup()
|
||||
await bot.send_message(tg_id, message, reply_markup=keyboard)
|
||||
|
||||
await bot.send_message(tg_id, message, reply_markup=keyboard.as_markup())
|
||||
logger.info(f"Уведомление отправлено пользователю {tg_id}.")
|
||||
|
||||
await conn.execute(
|
||||
"UPDATE keys SET notified = TRUE WHERE client_id = $1",
|
||||
record["client_id"],
|
||||
)
|
||||
logger.info(
|
||||
f"Обновлено поле notified для клиента {record['client_id']}.")
|
||||
except TelegramForbiddenError:
|
||||
logger.warning(f"Бот заблокирован пользователем {tg_id}. Записываем в blocked_users.")
|
||||
await add_blocked_user(tg_id, conn)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
logger.debug(
|
||||
f"Ошибка при отправке уведомления пользователю {tg_id}: {e}"
|
||||
)
|
||||
continue
|
||||
|
||||
await conn.execute(
|
||||
"UPDATE keys SET notified = TRUE WHERE client_id = $1",
|
||||
record["client_id"],
|
||||
)
|
||||
logger.info(f"Обновлено поле notified для клиента {record['client_id']}.")
|
||||
|
||||
await asyncio.sleep(1)
|
||||
await asyncio.gather(*(process_record(record) for record in records))
|
||||
logger.info("Обработка всех уведомлений за 10 часов завершена.")
|
||||
|
||||
|
||||
async def notify_24h_keys(
|
||||
@@ -162,13 +216,14 @@ async def notify_24h_keys(
|
||||
"""
|
||||
SELECT tg_id, email, expiry_time, client_id, server_id FROM keys
|
||||
WHERE expiry_time <= $1 AND expiry_time > $2 AND notified_24h = FALSE
|
||||
""",
|
||||
""",
|
||||
threshold_time_24h,
|
||||
current_time,
|
||||
)
|
||||
|
||||
logger.info(f"Найдено {len(records_24h)} ключей для уведомления за 24 часа.")
|
||||
for record in records_24h:
|
||||
|
||||
async def process_record(record):
|
||||
tg_id = record["tg_id"]
|
||||
email = record["email"]
|
||||
expiry_time = record["expiry_time"]
|
||||
@@ -191,7 +246,55 @@ async def notify_24h_keys(
|
||||
expiry_date=expiry_date.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
)
|
||||
|
||||
if not await is_bot_blocked(bot, tg_id) and not DEV_MODE:
|
||||
balance = await get_balance(tg_id)
|
||||
|
||||
if balance >= RENEWAL_PLANS["1"]["price"]:
|
||||
try:
|
||||
await update_balance(tg_id, -RENEWAL_PLANS["1"]["price"])
|
||||
new_expiry_time = int(
|
||||
(datetime.utcnow() + timedelta(days=30)).timestamp() * 1000
|
||||
)
|
||||
await update_key_expiry(record["client_id"], new_expiry_time)
|
||||
|
||||
servers = await get_servers_from_db()
|
||||
|
||||
for cluster_id in servers:
|
||||
await renew_key_in_cluster(
|
||||
cluster_id, email, record["client_id"], new_expiry_time, TOTAL_GB
|
||||
)
|
||||
logger.info(
|
||||
f"Ключ для пользователя {tg_id} успешно продлен в кластере {cluster_id}."
|
||||
)
|
||||
|
||||
await conn.execute(
|
||||
"""
|
||||
UPDATE keys
|
||||
SET notified_24h = FALSE, notified = FALSE
|
||||
WHERE client_id = $1
|
||||
""",
|
||||
record["client_id"],
|
||||
)
|
||||
|
||||
keyboard = InlineKeyboardBuilder()
|
||||
keyboard.row(
|
||||
types.InlineKeyboardButton(
|
||||
text="👤 Личный кабинет", callback_data="profile"
|
||||
)
|
||||
)
|
||||
await bot.send_message(
|
||||
tg_id,
|
||||
text=KEY_RENEWED,
|
||||
reply_markup=keyboard.as_markup(),
|
||||
)
|
||||
logger.info(
|
||||
f"Уведомление об успешном продлении отправлено клиенту {tg_id}."
|
||||
)
|
||||
except TelegramForbiddenError:
|
||||
logger.warning(f"Бот заблокирован пользователем {tg_id}. Записываем в blocked_users.")
|
||||
await add_blocked_user(tg_id, conn)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при продлении подписки для клиента {tg_id}: {e}")
|
||||
else:
|
||||
try:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
@@ -214,22 +317,27 @@ async def notify_24h_keys(
|
||||
)
|
||||
keyboard = builder.as_markup()
|
||||
await bot.send_message(tg_id, message_24h, reply_markup=keyboard)
|
||||
logger.info(f"Уведомление за 24 часа отправлено пользователю {tg_id}.")
|
||||
logger.info(
|
||||
f"Уведомление за 24 часа отправлено пользователю {tg_id}."
|
||||
)
|
||||
except TelegramForbiddenError:
|
||||
logger.warning(f"Бот заблокирован пользователем {tg_id}. Записываем в blocked_users.")
|
||||
await add_blocked_user(tg_id, conn)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Ошибка при отправке уведомления за 24 часа пользователю {tg_id}: {e}"
|
||||
)
|
||||
continue
|
||||
|
||||
await conn.execute(
|
||||
"UPDATE keys SET notified_24h = TRUE WHERE client_id = $1",
|
||||
record["client_id"],
|
||||
)
|
||||
logger.info(
|
||||
f"Обновлено поле notified_24h для клиента {record['client_id']}."
|
||||
)
|
||||
await conn.execute(
|
||||
"UPDATE keys SET notified_24h = TRUE WHERE client_id = $1",
|
||||
record["client_id"],
|
||||
)
|
||||
logger.info(
|
||||
f"Обновлено поле notified_24h для клиента {record['client_id']}."
|
||||
)
|
||||
|
||||
await asyncio.sleep(1)
|
||||
await asyncio.gather(*(process_record(record) for record in records_24h))
|
||||
logger.info("Обработка всех уведомлений за 24 часа завершена.")
|
||||
|
||||
|
||||
async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection):
|
||||
@@ -257,7 +365,7 @@ async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection):
|
||||
tg_id, "inactive_trial", hours=24, session=conn
|
||||
)
|
||||
|
||||
if can_notify and not await is_bot_blocked(bot, tg_id):
|
||||
if can_notify:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
types.InlineKeyboardButton(
|
||||
@@ -279,32 +387,45 @@ async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection):
|
||||
"💡 Нажми на кнопку ниже, чтобы активировать пробный доступ."
|
||||
)
|
||||
|
||||
await bot.send_message(tg_id, message, reply_markup=keyboard)
|
||||
logger.info(f"Отправлено уведомление неактивному пользователю {tg_id}.")
|
||||
try:
|
||||
await bot.send_message(tg_id, message, reply_markup=keyboard)
|
||||
logger.info(f"Отправлено уведомление неактивному пользователю {tg_id}.")
|
||||
await add_notification(tg_id, "inactive_trial", session=conn)
|
||||
|
||||
await add_notification(tg_id, "inactive_trial", session=conn)
|
||||
except TelegramForbiddenError:
|
||||
logger.warning(f"Бот заблокирован пользователем {tg_id}. Добавляем в blocked_users.")
|
||||
await add_blocked_user(tg_id, conn)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при отправке уведомления пользователю {tg_id}: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Ошибка при отправке уведомления неактивному пользователю {tg_id}: {e}"
|
||||
)
|
||||
logger.error(f"Ошибка при обработке пользователя {tg_id}: {e}")
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time: float):
|
||||
logger.info("Проверка истекших ключей...")
|
||||
logger.info("Проверка подписок, срок действия которых скоро истекает...")
|
||||
|
||||
threshold_time = int((datetime.utcnow() + timedelta(minutes=45)).timestamp() * 1000)
|
||||
|
||||
expiring_keys = await conn.fetch(
|
||||
"""
|
||||
SELECT tg_id, client_id, expiry_time, email FROM keys
|
||||
WHERE expiry_time <= $1
|
||||
WHERE expiry_time <= $1 AND expiry_time > $2
|
||||
""",
|
||||
threshold_time,
|
||||
current_time,
|
||||
)
|
||||
logger.info(f"current_time {current_time}")
|
||||
logger.info(f"Найдено {len(expiring_keys)} истекающих ключей.")
|
||||
|
||||
await asyncio.gather(*[process_key(record, bot, conn) for record in expiring_keys])
|
||||
logger.info(f"Найдено {len(expiring_keys)} подписок, срок действия которых скоро истекает.")
|
||||
|
||||
for record in expiring_keys:
|
||||
try:
|
||||
await process_key(record, bot, conn)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обработке подписки {record['client_id']}: {e}")
|
||||
|
||||
|
||||
|
||||
async def process_key(record, bot, conn):
|
||||
@@ -318,8 +439,11 @@ async def process_key(record, bot, conn):
|
||||
time_left = expiry_date - current_date
|
||||
|
||||
logger.info(
|
||||
f"Время истечения ключа: {expiry_time} (дата: {expiry_date}), Текущее время: {current_date}, Оставшееся время: {time_left}"
|
||||
f"Время истечения ключа: {expiry_time} (UTC: {expiry_date}), "
|
||||
f"Текущее время (UTC): {current_date}, "
|
||||
f"Оставшееся время: {time_left}"
|
||||
)
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
@@ -395,6 +519,7 @@ async def process_key(record, bot, conn):
|
||||
logger.error(f"Ошибка при обработке ключа для клиента {tg_id}: {e}")
|
||||
|
||||
|
||||
|
||||
async def check_online_users():
|
||||
servers = await get_servers_from_db()
|
||||
|
||||
@@ -413,29 +538,3 @@ async def check_online_users():
|
||||
logger.error(
|
||||
f"Не удалось проверить пользователей на сервере {server_id}: {e}"
|
||||
)
|
||||
|
||||
|
||||
async def update_all_keys():
|
||||
try:
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
keys = await conn.fetch("SELECT tg_id, client_id, email, expiry_time, server_id FROM keys")
|
||||
|
||||
for key in keys:
|
||||
tg_id = key['tg_id']
|
||||
client_id = key['client_id']
|
||||
email = key['email']
|
||||
expiry_time = key['expiry_time']
|
||||
cluster_id = key['server_id']
|
||||
|
||||
try:
|
||||
await update_key_on_cluster(tg_id, client_id, email, expiry_time, cluster_id)
|
||||
await store_key(tg_id, client_id, email, expiry_time, key['key'], cluster_id, conn)
|
||||
logger.info(f"Ключ {client_id} успешно обновлен и сохранен")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обновлении и сохранении ключа {client_id}: {e}")
|
||||
|
||||
logger.info("Все ключи успешно обновлены и сохранены")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обновлении всех ключей: {e}")
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
@@ -5,7 +5,6 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from config import (
|
||||
CRYPTO_BOT_ENABLE,
|
||||
DONATIONS_ENABLE,
|
||||
FREEKASSA_ENABLE,
|
||||
ROBOKASSA_ENABLE,
|
||||
STARS_ENABLE,
|
||||
YOOKASSA_ENABLE,
|
||||
@@ -33,13 +32,6 @@ async def handle_pay(callback_query: CallbackQuery):
|
||||
callback_data="pay_yoomoney",
|
||||
)
|
||||
)
|
||||
if FREEKASSA_ENABLE:
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="🌐 FreeKassa: множество способов",
|
||||
callback_data="pay_freekassa",
|
||||
)
|
||||
)
|
||||
if CRYPTO_BOT_ENABLE:
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
|
||||
@@ -4,7 +4,6 @@ from aiogram import Router
|
||||
|
||||
from config import (
|
||||
CRYPTO_BOT_ENABLE,
|
||||
FREEKASSA_ENABLE,
|
||||
ROBOKASSA_ENABLE,
|
||||
STARS_ENABLE,
|
||||
YOOKASSA_ENABLE,
|
||||
|
||||
+388
-375
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+92
-92
@@ -10076,7 +10076,7 @@ static PyObject *__pyx_gb_8handlers_8payments_4gift_22generator6(__pyx_Coroutine
|
||||
* logger.info(f": {data.get('message', ' .')}")
|
||||
* return False # <<<<<<<<<<<<<<
|
||||
* elif response.status in [502, 404]:
|
||||
* logger.info(f" .")
|
||||
* logger.info(" .")
|
||||
*/
|
||||
__Pyx_XDECREF(__pyx_r);
|
||||
__pyx_r = NULL; __Pyx_ReturnWithStopIteration(Py_False);
|
||||
@@ -10096,7 +10096,7 @@ static PyObject *__pyx_gb_8handlers_8payments_4gift_22generator6(__pyx_Coroutine
|
||||
* logger.info(f": {data.get('message', ' .')}")
|
||||
* return False
|
||||
* elif response.status in [502, 404]: # <<<<<<<<<<<<<<
|
||||
* logger.info(f" .")
|
||||
* logger.info(" .")
|
||||
* return True
|
||||
*/
|
||||
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_response, __pyx_n_s_status); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 260, __pyx_L27_error)
|
||||
@@ -10117,7 +10117,7 @@ static PyObject *__pyx_gb_8handlers_8payments_4gift_22generator6(__pyx_Coroutine
|
||||
/* "handlers/payments/gift.py":261
|
||||
* return False
|
||||
* elif response.status in [502, 404]:
|
||||
* logger.info(f" .") # <<<<<<<<<<<<<<
|
||||
* logger.info(" .") # <<<<<<<<<<<<<<
|
||||
* return True
|
||||
* else:
|
||||
*/
|
||||
@@ -10152,7 +10152,7 @@ static PyObject *__pyx_gb_8handlers_8payments_4gift_22generator6(__pyx_Coroutine
|
||||
|
||||
/* "handlers/payments/gift.py":262
|
||||
* elif response.status in [502, 404]:
|
||||
* logger.info(f" .")
|
||||
* logger.info(" .")
|
||||
* return True # <<<<<<<<<<<<<<
|
||||
* else:
|
||||
* logger.info(f" : {response.status}")
|
||||
@@ -10165,7 +10165,7 @@ static PyObject *__pyx_gb_8handlers_8payments_4gift_22generator6(__pyx_Coroutine
|
||||
* logger.info(f": {data.get('message', ' .')}")
|
||||
* return False
|
||||
* elif response.status in [502, 404]: # <<<<<<<<<<<<<<
|
||||
* logger.info(f" .")
|
||||
* logger.info(" .")
|
||||
* return True
|
||||
*/
|
||||
}
|
||||
@@ -14036,7 +14036,7 @@ if (!__Pyx_RefNanny) {
|
||||
* from aiogram import F, Router, types
|
||||
* from aiogram.fsm.context import FSMContext # <<<<<<<<<<<<<<
|
||||
* from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
* from handlers.buttons.gifts import GIFT, BACK, PROFILE, MY_GIFTS, GIFTS_ABOUT
|
||||
*
|
||||
*/
|
||||
__pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
@@ -14056,8 +14056,8 @@ if (!__Pyx_RefNanny) {
|
||||
* from aiogram import F, Router, types
|
||||
* from aiogram.fsm.context import FSMContext
|
||||
* from aiogram.utils.keyboard import InlineKeyboardBuilder # <<<<<<<<<<<<<<
|
||||
* from handlers.buttons.gifts import GIFT, BACK, PROFILE, MY_GIFTS, GIFTS_ABOUT
|
||||
*
|
||||
* from config import CLIENT_CODE, RENEWAL_PRICES
|
||||
*/
|
||||
__pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
@@ -14073,149 +14073,149 @@ if (!__Pyx_RefNanny) {
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
|
||||
/* "handlers/payments/gift.py":12
|
||||
* from aiogram.fsm.context import FSMContext
|
||||
/* "handlers/payments/gift.py":13
|
||||
* from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
* from handlers.buttons.gifts import GIFT, BACK, PROFILE, MY_GIFTS, GIFTS_ABOUT # <<<<<<<<<<<<<<
|
||||
*
|
||||
* from config import CLIENT_CODE, RENEWAL_PRICES
|
||||
* from config import CLIENT_CODE, RENEWAL_PRICES # <<<<<<<<<<<<<<
|
||||
* from database import get_balance, store_gift_link, update_balance
|
||||
* from handlers.buttons.gifts import BACK, GIFT, GIFTS_ABOUT, MY_GIFTS, PROFILE
|
||||
*/
|
||||
__pyx_t_3 = PyList_New(5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__pyx_t_3 = PyList_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 13, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
__Pyx_INCREF(__pyx_n_s_GIFT);
|
||||
__Pyx_GIVEREF(__pyx_n_s_GIFT);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_GIFT)) __PYX_ERR(0, 12, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_BACK);
|
||||
__Pyx_GIVEREF(__pyx_n_s_BACK);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 1, __pyx_n_s_BACK)) __PYX_ERR(0, 12, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_PROFILE);
|
||||
__Pyx_GIVEREF(__pyx_n_s_PROFILE);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 2, __pyx_n_s_PROFILE)) __PYX_ERR(0, 12, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_MY_GIFTS);
|
||||
__Pyx_GIVEREF(__pyx_n_s_MY_GIFTS);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 3, __pyx_n_s_MY_GIFTS)) __PYX_ERR(0, 12, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_GIFTS_ABOUT);
|
||||
__Pyx_GIVEREF(__pyx_n_s_GIFTS_ABOUT);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 4, __pyx_n_s_GIFTS_ABOUT)) __PYX_ERR(0, 12, __pyx_L1_error);
|
||||
__pyx_t_2 = __Pyx_Import(__pyx_n_s_handlers_buttons_gifts, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__Pyx_INCREF(__pyx_n_s_CLIENT_CODE);
|
||||
__Pyx_GIVEREF(__pyx_n_s_CLIENT_CODE);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_CLIENT_CODE)) __PYX_ERR(0, 13, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_RENEWAL_PRICES);
|
||||
__Pyx_GIVEREF(__pyx_n_s_RENEWAL_PRICES);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 1, __pyx_n_s_RENEWAL_PRICES)) __PYX_ERR(0, 13, __pyx_L1_error);
|
||||
__pyx_t_2 = __Pyx_Import(__pyx_n_s_config, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 13, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_GIFT); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_CLIENT_CODE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 13, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_GIFT, __pyx_t_3) < 0) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_CLIENT_CODE, __pyx_t_3) < 0) __PYX_ERR(0, 13, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_BACK); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_RENEWAL_PRICES); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 13, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_BACK, __pyx_t_3) < 0) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_PROFILE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_PROFILE, __pyx_t_3) < 0) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_MY_GIFTS); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_MY_GIFTS, __pyx_t_3) < 0) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_GIFTS_ABOUT); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_GIFTS_ABOUT, __pyx_t_3) < 0) __PYX_ERR(0, 12, __pyx_L1_error)
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_RENEWAL_PRICES, __pyx_t_3) < 0) __PYX_ERR(0, 13, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
|
||||
/* "handlers/payments/gift.py":14
|
||||
* from handlers.buttons.gifts import GIFT, BACK, PROFILE, MY_GIFTS, GIFTS_ABOUT
|
||||
*
|
||||
* from config import CLIENT_CODE, RENEWAL_PRICES # <<<<<<<<<<<<<<
|
||||
* from database import get_balance, store_gift_link, update_balance
|
||||
* from handlers.texts import get_gift_link, GIFTS_TEXT_TEMPLATE
|
||||
* from config import CLIENT_CODE, RENEWAL_PRICES
|
||||
* from database import get_balance, store_gift_link, update_balance # <<<<<<<<<<<<<<
|
||||
* from handlers.buttons.gifts import BACK, GIFT, GIFTS_ABOUT, MY_GIFTS, PROFILE
|
||||
* from handlers.texts import GIFTS_TEXT_TEMPLATE, get_gift_link
|
||||
*/
|
||||
__pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__pyx_t_2 = PyList_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
__Pyx_INCREF(__pyx_n_s_CLIENT_CODE);
|
||||
__Pyx_GIVEREF(__pyx_n_s_CLIENT_CODE);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_CLIENT_CODE)) __PYX_ERR(0, 14, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_RENEWAL_PRICES);
|
||||
__Pyx_GIVEREF(__pyx_n_s_RENEWAL_PRICES);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_RENEWAL_PRICES)) __PYX_ERR(0, 14, __pyx_L1_error);
|
||||
__pyx_t_3 = __Pyx_Import(__pyx_n_s_config, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_INCREF(__pyx_n_s_get_balance);
|
||||
__Pyx_GIVEREF(__pyx_n_s_get_balance);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_get_balance)) __PYX_ERR(0, 14, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_store_gift_link);
|
||||
__Pyx_GIVEREF(__pyx_n_s_store_gift_link);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_store_gift_link)) __PYX_ERR(0, 14, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_update_balance);
|
||||
__Pyx_GIVEREF(__pyx_n_s_update_balance);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_update_balance)) __PYX_ERR(0, 14, __pyx_L1_error);
|
||||
__pyx_t_3 = __Pyx_Import(__pyx_n_s_database, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_CLIENT_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_get_balance); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_CLIENT_CODE, __pyx_t_2) < 0) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_balance, __pyx_t_2) < 0) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_RENEWAL_PRICES); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_store_gift_link); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_RENEWAL_PRICES, __pyx_t_2) < 0) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_store_gift_link, __pyx_t_2) < 0) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_update_balance); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_update_balance, __pyx_t_2) < 0) __PYX_ERR(0, 14, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
|
||||
/* "handlers/payments/gift.py":15
|
||||
*
|
||||
* from config import CLIENT_CODE, RENEWAL_PRICES
|
||||
* from database import get_balance, store_gift_link, update_balance # <<<<<<<<<<<<<<
|
||||
* from handlers.texts import get_gift_link, GIFTS_TEXT_TEMPLATE
|
||||
* from database import get_balance, store_gift_link, update_balance
|
||||
* from handlers.buttons.gifts import BACK, GIFT, GIFTS_ABOUT, MY_GIFTS, PROFILE # <<<<<<<<<<<<<<
|
||||
* from handlers.texts import GIFTS_TEXT_TEMPLATE, get_gift_link
|
||||
* from logger import logger
|
||||
*/
|
||||
__pyx_t_3 = PyList_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__pyx_t_3 = PyList_New(5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
__Pyx_INCREF(__pyx_n_s_get_balance);
|
||||
__Pyx_GIVEREF(__pyx_n_s_get_balance);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_get_balance)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_store_gift_link);
|
||||
__Pyx_GIVEREF(__pyx_n_s_store_gift_link);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 1, __pyx_n_s_store_gift_link)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_update_balance);
|
||||
__Pyx_GIVEREF(__pyx_n_s_update_balance);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 2, __pyx_n_s_update_balance)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__pyx_t_2 = __Pyx_Import(__pyx_n_s_database, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_INCREF(__pyx_n_s_BACK);
|
||||
__Pyx_GIVEREF(__pyx_n_s_BACK);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_BACK)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_GIFT);
|
||||
__Pyx_GIVEREF(__pyx_n_s_GIFT);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 1, __pyx_n_s_GIFT)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_GIFTS_ABOUT);
|
||||
__Pyx_GIVEREF(__pyx_n_s_GIFTS_ABOUT);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 2, __pyx_n_s_GIFTS_ABOUT)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_MY_GIFTS);
|
||||
__Pyx_GIVEREF(__pyx_n_s_MY_GIFTS);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 3, __pyx_n_s_MY_GIFTS)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_PROFILE);
|
||||
__Pyx_GIVEREF(__pyx_n_s_PROFILE);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 4, __pyx_n_s_PROFILE)) __PYX_ERR(0, 15, __pyx_L1_error);
|
||||
__pyx_t_2 = __Pyx_Import(__pyx_n_s_handlers_buttons_gifts, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_get_balance); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_BACK); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_balance, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_BACK, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_store_gift_link); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_GIFT); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_store_gift_link, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_GIFT, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_update_balance); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_GIFTS_ABOUT); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_update_balance, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_GIFTS_ABOUT, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_MY_GIFTS); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_MY_GIFTS, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_PROFILE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_PROFILE, __pyx_t_3) < 0) __PYX_ERR(0, 15, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
|
||||
/* "handlers/payments/gift.py":16
|
||||
* from config import CLIENT_CODE, RENEWAL_PRICES
|
||||
* from database import get_balance, store_gift_link, update_balance
|
||||
* from handlers.texts import get_gift_link, GIFTS_TEXT_TEMPLATE # <<<<<<<<<<<<<<
|
||||
* from handlers.buttons.gifts import BACK, GIFT, GIFTS_ABOUT, MY_GIFTS, PROFILE
|
||||
* from handlers.texts import GIFTS_TEXT_TEMPLATE, get_gift_link # <<<<<<<<<<<<<<
|
||||
* from logger import logger
|
||||
*
|
||||
*/
|
||||
__pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
__Pyx_INCREF(__pyx_n_s_get_gift_link);
|
||||
__Pyx_GIVEREF(__pyx_n_s_get_gift_link);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_get_gift_link)) __PYX_ERR(0, 16, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_GIFTS_TEXT_TEMPLATE);
|
||||
__Pyx_GIVEREF(__pyx_n_s_GIFTS_TEXT_TEMPLATE);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_GIFTS_TEXT_TEMPLATE)) __PYX_ERR(0, 16, __pyx_L1_error);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_GIFTS_TEXT_TEMPLATE)) __PYX_ERR(0, 16, __pyx_L1_error);
|
||||
__Pyx_INCREF(__pyx_n_s_get_gift_link);
|
||||
__Pyx_GIVEREF(__pyx_n_s_get_gift_link);
|
||||
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_get_gift_link)) __PYX_ERR(0, 16, __pyx_L1_error);
|
||||
__pyx_t_3 = __Pyx_Import(__pyx_n_s_handlers_texts, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_3);
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_get_gift_link); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_gift_link, __pyx_t_2) < 0) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_GIFTS_TEXT_TEMPLATE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_GIFTS_TEXT_TEMPLATE, __pyx_t_2) < 0) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_get_gift_link); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_GOTREF(__pyx_t_2);
|
||||
if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_gift_link, __pyx_t_2) < 0) __PYX_ERR(0, 16, __pyx_L1_error)
|
||||
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
|
||||
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
|
||||
|
||||
/* "handlers/payments/gift.py":17
|
||||
* from database import get_balance, store_gift_link, update_balance
|
||||
* from handlers.texts import get_gift_link, GIFTS_TEXT_TEMPLATE
|
||||
* from handlers.buttons.gifts import BACK, GIFT, GIFTS_ABOUT, MY_GIFTS, PROFILE
|
||||
* from handlers.texts import GIFTS_TEXT_TEMPLATE, get_gift_link
|
||||
* from logger import logger # <<<<<<<<<<<<<<
|
||||
*
|
||||
* router = Router()
|
||||
|
||||
Binary file not shown.
+2435
-460
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+3600
-2176
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+62
-50
@@ -1,13 +1,14 @@
|
||||
import os
|
||||
|
||||
import asyncpg
|
||||
from aiogram import F, Router, types
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import BufferedInputFile, InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from config import NEWS_MESSAGE, RENEWAL_PLANS
|
||||
from database import get_balance, get_key_count, get_referral_stats
|
||||
from handlers.buttons.profile import ADD_SUB, GIFTS, INSTRUCTIONS, INVITE, MAIN_MENU, MY_SUBS, PAYMENT, TARRIFS
|
||||
from config import DATABASE_URL, NEWS_MESSAGE, RENEWAL_PLANS
|
||||
from database import get_balance, get_key_count, get_referral_stats, get_trial
|
||||
from handlers.buttons.profile import ADD_SUB, GIFTS, INSTRUCTIONS, INVITE, MAIN_MENU, MY_SUBS, PAYMENT
|
||||
from handlers.texts import get_referral_link, invite_message_send, profile_message_send
|
||||
|
||||
router = Router()
|
||||
@@ -33,64 +34,75 @@ async def process_callback_view_profile(
|
||||
if balance is None:
|
||||
balance = 0
|
||||
|
||||
profile_message = profile_message_send(username, chat_id, int(balance), key_count)
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
trial_status = await get_trial(chat_id, conn)
|
||||
|
||||
if key_count == 0:
|
||||
profile_message += "\n<pre>🔧 <i>Нажмите кнопку ➕ Устройство, чтобы настроить VPN-подключение</i></pre>"
|
||||
else:
|
||||
profile_message += f"\n<pre> <i>{NEWS_MESSAGE}</i></pre>"
|
||||
profile_message = profile_message_send(username, chat_id, int(balance), key_count)
|
||||
|
||||
if key_count == 0:
|
||||
profile_message += "\n<pre>🔧 <i>Нажмите кнопку ➕ Устройство, чтобы настроить VPN-подключение</i></pre>"
|
||||
else:
|
||||
profile_message += f"\n<pre> <i>{NEWS_MESSAGE}</i></pre>"
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
|
||||
if trial_status == 0 or key_count == 0:
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=ADD_SUB, callback_data="create_key")
|
||||
)
|
||||
else:
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=MY_SUBS, callback_data="view_keys")
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=ADD_SUB, callback_data="create_key"),
|
||||
InlineKeyboardButton(text=MY_SUBS, callback_data="view_keys"),
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT,
|
||||
callback_data="pay",
|
||||
)
|
||||
)
|
||||
builder.row()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=INVITE, callback_data="invite"),
|
||||
InlineKeyboardButton(text=GIFTS, callback_data="gifts"),
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=TARRIFS, callback_data="view_tariffs"),
|
||||
InlineKeyboardButton(text=INSTRUCTIONS, callback_data="instructions"),
|
||||
)
|
||||
if admin:
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🔧 Администратор", callback_data="admin")
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT,
|
||||
callback_data="pay",
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="start"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=INVITE, callback_data="invite"),
|
||||
InlineKeyboardButton(text=GIFTS, callback_data="gifts"),
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=INSTRUCTIONS, callback_data="instructions"),
|
||||
)
|
||||
if admin:
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🔧 Администратор", callback_data="admin")
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="start"))
|
||||
|
||||
if os.path.isfile(image_path):
|
||||
with open(image_path, "rb") as image_file:
|
||||
if os.path.isfile(image_path):
|
||||
with open(image_path, "rb") as image_file:
|
||||
if is_callback:
|
||||
await callback_query_or_message.message.answer_photo(
|
||||
photo=BufferedInputFile(image_file.read(), filename="pic.jpg"),
|
||||
caption=profile_message,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
else:
|
||||
await callback_query_or_message.answer_photo(
|
||||
photo=BufferedInputFile(image_file.read(), filename="pic.jpg"),
|
||||
caption=profile_message,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
else:
|
||||
if is_callback:
|
||||
await callback_query_or_message.message.answer_photo(
|
||||
photo=BufferedInputFile(image_file.read(), filename="pic.jpg"),
|
||||
caption=profile_message,
|
||||
await callback_query_or_message.message.answer(
|
||||
text=profile_message,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
else:
|
||||
await callback_query_or_message.answer_photo(
|
||||
photo=BufferedInputFile(image_file.read(), filename="pic.jpg"),
|
||||
caption=profile_message,
|
||||
await callback_query_or_message.answer(
|
||||
text=profile_message,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
else:
|
||||
if is_callback:
|
||||
await callback_query_or_message.message.answer(
|
||||
text=profile_message,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
else:
|
||||
await callback_query_or_message.answer(
|
||||
text=profile_message,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
|
||||
|
||||
|
||||
+14
-6
@@ -23,6 +23,14 @@ from config import (
|
||||
SUPPORT_CHAT_URL,
|
||||
)
|
||||
from database import add_connection, add_referral, check_connection_exists, get_trial, use_trial
|
||||
from handlers.buttons.add_subscribe import (
|
||||
DOWNLOAD_ANDROID_BUTTON,
|
||||
DOWNLOAD_IOS_BUTTON,
|
||||
IMPORT_ANDROID,
|
||||
IMPORT_IOS,
|
||||
PC_BUTTON,
|
||||
TV_BUTTON,
|
||||
)
|
||||
from handlers.keys.key_management import create_key
|
||||
from handlers.keys.trial_key import create_trial_key
|
||||
from handlers.texts import INSTRUCTIONS_TRIAL, WELCOME_TEXT, get_about_vpn
|
||||
@@ -201,25 +209,25 @@ async def handle_connect_vpn(callback_query: CallbackQuery, session: Any):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="💬 Поддержка", url=SUPPORT_CHAT_URL))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🍏 Скачать для iOS", url=DOWNLOAD_IOS),
|
||||
InlineKeyboardButton(text="🤖 Скачать для Android", url=DOWNLOAD_ANDROID),
|
||||
InlineKeyboardButton(text=DOWNLOAD_IOS_BUTTON, url=DOWNLOAD_IOS),
|
||||
InlineKeyboardButton(text=DOWNLOAD_ANDROID_BUTTON, url=DOWNLOAD_ANDROID),
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="🍏 Подключить на iOS",
|
||||
text=IMPORT_IOS,
|
||||
url=f'{CONNECT_IOS}{trial_key_info["key"]}',
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text="🤖 Подключить на Android",
|
||||
text=IMPORT_ANDROID,
|
||||
url=f'{CONNECT_ANDROID}{trial_key_info["key"]}',
|
||||
),
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="💻 Компьютеры", callback_data=f"connect_pc|{email}"
|
||||
text=PC_BUTTON, callback_data=f"connect_pc|{email}"
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text="📺 Андроид TV", callback_data=f"connect_tv|{email}"
|
||||
text=TV_BUTTON, callback_data=f"connect_tv|{email}"
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import json
|
||||
|
||||
import aiohttp
|
||||
import asyncpg
|
||||
|
||||
+2
-1
@@ -31,4 +31,5 @@ py3xui
|
||||
sqlalchemy
|
||||
robokassa
|
||||
ping3
|
||||
ruff
|
||||
ruff
|
||||
pytz
|
||||
+2
-2
@@ -8,7 +8,7 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from ping3 import ping
|
||||
|
||||
from bot import bot
|
||||
from config import ADMIN_ID, DATABASE_URL
|
||||
from config import ADMIN_ID, DATABASE_URL, PING_TIME
|
||||
from database import get_servers_from_db
|
||||
from logger import logger
|
||||
|
||||
@@ -184,7 +184,7 @@ async def check_servers():
|
||||
)
|
||||
|
||||
logger.info("Завершена проверка всех серверов.")
|
||||
await asyncio.sleep(30)
|
||||
await asyncio.sleep(PING_TIME)
|
||||
|
||||
|
||||
def extract_host(api_url: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user