refactoring and minor improvements
This commit is contained in:
@@ -6,9 +6,9 @@ from typing import Optional, Tuple, Union
|
||||
|
||||
import aiofiles
|
||||
from aiogram.types import BufferedInputFile
|
||||
from config import ADMIN_ID, BACK_DIR, DB_NAME, DB_PASSWORD, DB_USER, PG_HOST, PG_PORT
|
||||
|
||||
from bot import bot
|
||||
from config import ADMIN_ID, BACK_DIR, DB_NAME, DB_PASSWORD, DB_USER, PG_HOST, PG_PORT
|
||||
from logger import logger
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ from aiogram.filters import ExceptionTypeFilter
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
from aiogram.types import BufferedInputFile, ErrorEvent
|
||||
from aiogram.utils.markdown import hbold
|
||||
from config import ADMIN_ID, API_TOKEN
|
||||
|
||||
from config import ADMIN_ID, API_TOKEN
|
||||
from filters.private import IsPrivateFilter
|
||||
from logger import logger
|
||||
from middlewares import register_middleware
|
||||
|
||||
@@ -2,8 +2,8 @@ from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import py3xui
|
||||
from config import LIMIT_IP, SUPERNODE
|
||||
|
||||
from config import LIMIT_IP, SUPERNODE
|
||||
from logger import logger
|
||||
|
||||
|
||||
|
||||
+22
-16
@@ -4,8 +4,8 @@ from typing import Any
|
||||
|
||||
import asyncpg
|
||||
import pytz
|
||||
from config import CASHBACK, CHECK_REFERRAL_REWARD_ISSUED, DATABASE_URL, REFERRAL_BONUS_PERCENTAGES
|
||||
|
||||
from config import CASHBACK, CHECK_REFERRAL_REWARD_ISSUED, DATABASE_URL, REFERRAL_BONUS_PERCENTAGES
|
||||
from logger import logger
|
||||
|
||||
|
||||
@@ -848,12 +848,16 @@ async def get_total_referral_bonus(conn, referrer_tg_id: int, max_levels: int) -
|
||||
SELECT
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
{" ".join([
|
||||
f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]} * ep.amount"
|
||||
if isinstance(REFERRAL_BONUS_PERCENTAGES[level], float)
|
||||
else f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]}"
|
||||
for level in REFERRAL_BONUS_PERCENTAGES
|
||||
])}
|
||||
{
|
||||
" ".join(
|
||||
[
|
||||
f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]} * ep.amount"
|
||||
if isinstance(REFERRAL_BONUS_PERCENTAGES[level], float)
|
||||
else f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]}"
|
||||
for level in REFERRAL_BONUS_PERCENTAGES
|
||||
]
|
||||
)
|
||||
}
|
||||
ELSE 0
|
||||
END
|
||||
), 0) AS total_bonus
|
||||
@@ -890,12 +894,16 @@ async def get_total_referral_bonus(conn, referrer_tg_id: int, max_levels: int) -
|
||||
SELECT
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
{" ".join([
|
||||
f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]} * p.amount"
|
||||
if isinstance(REFERRAL_BONUS_PERCENTAGES[level], float)
|
||||
else f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]}"
|
||||
for level in REFERRAL_BONUS_PERCENTAGES
|
||||
])}
|
||||
{
|
||||
" ".join(
|
||||
[
|
||||
f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]} * p.amount"
|
||||
if isinstance(REFERRAL_BONUS_PERCENTAGES[level], float)
|
||||
else f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]}"
|
||||
for level in REFERRAL_BONUS_PERCENTAGES
|
||||
]
|
||||
)
|
||||
}
|
||||
ELSE 0
|
||||
END
|
||||
), 0) AS total_bonus
|
||||
@@ -1133,7 +1141,7 @@ async def upsert_user(
|
||||
is_bot = EXCLUDED.is_bot,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
RETURNING
|
||||
id, tg_id, username, first_name, last_name, language_code,
|
||||
tg_id, username, first_name, last_name, language_code,
|
||||
is_bot, created_at, updated_at
|
||||
""",
|
||||
tg_id,
|
||||
@@ -1146,13 +1154,11 @@ async def upsert_user(
|
||||
|
||||
logger.debug(f"Успешно обновлена информация о пользователе {tg_id}")
|
||||
|
||||
# Преобразуем результат в словарь
|
||||
return dict(user_data)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обновлении информации о пользователе {tg_id}: {e}")
|
||||
raise
|
||||
finally:
|
||||
# Закрываем соединение только если мы его создали
|
||||
if conn and close_conn:
|
||||
await conn.close()
|
||||
logger.debug("Закрытие подключения к базе данных")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from aiogram.filters import BaseFilter
|
||||
from aiogram.types import Message
|
||||
|
||||
from config import ADMIN_ID
|
||||
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ from aiogram import F, Router, types
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.types import CallbackQuery, Message
|
||||
from config import USERNAME_BOT
|
||||
|
||||
from config import USERNAME_BOT
|
||||
from database import create_coupon, delete_coupon, get_all_coupons
|
||||
from filters.admin import IsAdminFilter
|
||||
from keyboards.admin.coupons_kb import AdminCouponDeleteCallback, build_coupons_kb, build_coupons_list_kb
|
||||
|
||||
@@ -6,10 +6,10 @@ from aiogram import F, Router, types
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.types import CallbackQuery, Message
|
||||
from config import ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL
|
||||
from py3xui import AsyncApi
|
||||
|
||||
from backup import create_backup_and_send_to_admins
|
||||
from config import ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL
|
||||
from database import check_unique_server_name, delete_server, get_servers
|
||||
from filters.admin import IsAdminFilter
|
||||
from handlers.keys.key_utils import create_key_on_cluster
|
||||
|
||||
@@ -8,8 +8,8 @@ from aiogram.exceptions import TelegramBadRequest
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.types import CallbackQuery, Message
|
||||
from config import TOTAL_GB
|
||||
|
||||
from config import TOTAL_GB
|
||||
from database import (
|
||||
delete_key,
|
||||
delete_user_data,
|
||||
|
||||
@@ -4,3 +4,6 @@ PROFILE = "👤 Личный кабинет"
|
||||
BACK = "В меню подарков"
|
||||
GIFTS_ABOUT = "<b>Дарите подарки и следите, чтобы они дошли до адресата! 🎄</b>"
|
||||
SHARE_GIFT = "🎁 Поделиться подарком"
|
||||
APPLY = "✅ Подтвердить"
|
||||
CANCEL = "❌ Отмена"
|
||||
NO_GIFTS = "У вас нет подарков."
|
||||
|
||||
+30
-21
@@ -6,35 +6,27 @@ from aiogram import F, Router
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import CallbackQuery, Message
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from config import CAPTCHA_EMOJIS
|
||||
|
||||
from config import CAPTCHA_EMOJIS
|
||||
from logger import logger
|
||||
|
||||
from .utils import edit_or_send_message
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
async def generate_captcha(message: Message, state: FSMContext):
|
||||
"""Генерирует новую капчу и сохраняет правильный ответ в состоянии
|
||||
|
||||
Пример словаря CAPTCHA_EMOJIS:
|
||||
{
|
||||
"🐶": "собаку", # Собака
|
||||
"🐱": "кошку", # Кошка
|
||||
"🐭": "мышь", # Мышь
|
||||
"🐹": "хомяка", # Хомяк
|
||||
"🐰": "кролика", # Кролик
|
||||
...
|
||||
}
|
||||
"""
|
||||
correct_emoji, correct_text = secrets.choice(list(CAPTCHA_EMOJIS.items()))
|
||||
|
||||
wrong_emojis = random.sample([e for e in CAPTCHA_EMOJIS.keys() if e != correct_emoji], 3)
|
||||
|
||||
all_emojis = [correct_emoji] + wrong_emojis
|
||||
random.shuffle(all_emojis)
|
||||
|
||||
await state.update_data(correct_emoji=correct_emoji)
|
||||
await state.update_data(message=message)
|
||||
await state.update_data(
|
||||
correct_emoji=correct_emoji,
|
||||
message_id=message.message_id,
|
||||
chat_id=message.chat.id,
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
for emoji in all_emojis:
|
||||
@@ -42,7 +34,7 @@ async def generate_captcha(message: Message, state: FSMContext):
|
||||
builder.adjust(2, 2)
|
||||
|
||||
return {
|
||||
"text": f"🔒 Для подтверждения что вы не робот, выберите кнопку с {correct_text}",
|
||||
"text": f"🔒 Для подтверждения, что вы не робот, выберите кнопку с {correct_text}",
|
||||
"markup": builder.as_markup(),
|
||||
}
|
||||
|
||||
@@ -54,12 +46,29 @@ async def check_captcha(callback: CallbackQuery, state: FSMContext, session: Any
|
||||
selected_emoji = callback.data.split("captcha_")[1]
|
||||
state_data = await state.get_data()
|
||||
correct_emoji = state_data.get("correct_emoji")
|
||||
message = state_data.get("message", callback.message)
|
||||
message_id = state_data.get("message_id")
|
||||
chat_id = state_data.get("chat_id")
|
||||
|
||||
if not message_id or not chat_id:
|
||||
target_message = callback.message
|
||||
else:
|
||||
try:
|
||||
target_message = await callback.bot.edit_message_text(
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
text=callback.message.text,
|
||||
)
|
||||
except Exception:
|
||||
target_message = callback.message
|
||||
|
||||
if selected_emoji == correct_emoji:
|
||||
logger.info(f"Пользователь {callback.message.chat.id} успешно прошел капчу")
|
||||
await start_command(message, state, session, admin, False)
|
||||
await start_command(target_message, state, session, admin, False)
|
||||
else:
|
||||
logger.warning(f"Пользователь {callback.message.chat.id} неверно ответил на капчу")
|
||||
captcha = await generate_captcha(message, state)
|
||||
await callback.message.answer(text=captcha["text"], reply_markup=captcha["markup"])
|
||||
captcha = await generate_captcha(target_message, state)
|
||||
await edit_or_send_message(
|
||||
target_message=target_message,
|
||||
text=captcha["text"],
|
||||
reply_markup=captcha["markup"],
|
||||
)
|
||||
|
||||
+19
-5
@@ -3,10 +3,12 @@ from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.types import CallbackQuery, InlineKeyboardButton, LabeledPrice, Message, PreCheckoutQuery
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from config import RUB_TO_XTR
|
||||
|
||||
from config import RUB_TO_XTR
|
||||
from logger import logger
|
||||
|
||||
from .utils import edit_or_send_message
|
||||
|
||||
|
||||
class DonateState(StatesGroup):
|
||||
entering_donate_amount = State()
|
||||
@@ -31,10 +33,15 @@ async def process_donate(callback_query: CallbackQuery, state: FSMContext):
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||
|
||||
await callback_query.message.answer(
|
||||
text="🌟 Поддержите наш проект! 💪\n\n"
|
||||
text = (
|
||||
"🌟 Поддержите наш проект! 💪\n\n"
|
||||
"💖 Каждый донат помогает развивать и улучшать сервис. "
|
||||
"🤝 Мы ценим вашу поддержку и работаем над тем, чтобы сделать наш продукт еще лучше. 🚀💡",
|
||||
"🤝 Мы ценим вашу поддержку и работаем над тем, чтобы сделать наш продукт еще лучше. 🚀💡"
|
||||
)
|
||||
|
||||
await edit_or_send_message(
|
||||
target_message=callback_query.message,
|
||||
text=text,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
|
||||
@@ -43,7 +50,14 @@ async def process_donate(callback_query: CallbackQuery, state: FSMContext):
|
||||
async def process_enter_donate_amount(callback_query: CallbackQuery, state: FSMContext):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="donate"))
|
||||
await callback_query.message.answer("💸 Введите сумму доната в рублях:", reply_markup=builder.as_markup())
|
||||
text = "💸 Введите сумму доната в рублях:"
|
||||
|
||||
await edit_or_send_message(
|
||||
target_message=callback_query.message,
|
||||
text=text,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
|
||||
await state.set_state(DonateState.entering_donate_amount)
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ from aiogram.types import (
|
||||
Message,
|
||||
)
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from config import CONNECT_MACOS, CONNECT_WINDOWS, SUPPORT_CHAT_URL
|
||||
|
||||
from config import CONNECT_MACOS, CONNECT_WINDOWS, SUPPORT_CHAT_URL
|
||||
from database import get_key_details
|
||||
from handlers.texts import (
|
||||
CONNECT_TV_TEXT,
|
||||
|
||||
@@ -8,6 +8,10 @@ from aiogram import F, Router
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from py3xui import AsyncApi
|
||||
|
||||
from bot import bot
|
||||
from client import delete_client
|
||||
from config import (
|
||||
ADMIN_PASSWORD,
|
||||
ADMIN_USERNAME,
|
||||
@@ -25,10 +29,6 @@ from config import (
|
||||
USE_COUNTRY_SELECTION,
|
||||
USE_NEW_PAYMENT_FLOW,
|
||||
)
|
||||
from py3xui import AsyncApi
|
||||
|
||||
from bot import bot
|
||||
from client import delete_client
|
||||
from database import (
|
||||
add_connection,
|
||||
check_connection_exists,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from config import ADMIN_PASSWORD, ADMIN_USERNAME, LIMIT_IP, PUBLIC_LINK, SUPERNODE, TOTAL_GB, USE_COUNTRY_SELECTION
|
||||
from py3xui import AsyncApi
|
||||
|
||||
from client import ClientConfig, add_client, delete_client, extend_client_key, get_client_traffic, toggle_client
|
||||
from config import ADMIN_PASSWORD, ADMIN_USERNAME, LIMIT_IP, PUBLIC_LINK, SUPERNODE, TOTAL_GB, USE_COUNTRY_SELECTION
|
||||
from database import get_servers, store_key
|
||||
from handlers.utils import get_least_loaded_cluster
|
||||
from logger import logger
|
||||
|
||||
@@ -9,6 +9,8 @@ import pytz
|
||||
from aiogram import F, Router, types
|
||||
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from bot import bot
|
||||
from config import (
|
||||
CONNECT_ANDROID,
|
||||
CONNECT_IOS,
|
||||
@@ -24,8 +26,6 @@ from config import (
|
||||
USE_COUNTRY_SELECTION,
|
||||
USE_NEW_PAYMENT_FLOW,
|
||||
)
|
||||
|
||||
from bot import bot
|
||||
from database import (
|
||||
check_server_name_by_cluster,
|
||||
create_temporary_data,
|
||||
|
||||
@@ -5,12 +5,12 @@ import re
|
||||
import time
|
||||
import urllib.parse
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
import aiohttp
|
||||
import asyncpg
|
||||
import pytz
|
||||
from aiohttp import web
|
||||
|
||||
from config import (
|
||||
DATABASE_URL,
|
||||
PROJECT_NAME,
|
||||
@@ -22,13 +22,11 @@ from config import (
|
||||
USE_COUNTRY_SELECTION,
|
||||
USERNAME_BOT,
|
||||
)
|
||||
|
||||
from database import get_key_details, get_servers
|
||||
from handlers.utils import convert_to_bytes
|
||||
from logger import logger
|
||||
|
||||
|
||||
# Функции для работы с URL и подписками
|
||||
async def fetch_url_content(url: str, identifier: str) -> list[str]:
|
||||
"""
|
||||
Получает содержимое подписки по URL и декодирует его.
|
||||
@@ -144,7 +142,6 @@ def get_transition_timestamp() -> int:
|
||||
return transition_timestamp_ms
|
||||
|
||||
|
||||
# Функции для обработки и форматирования данных
|
||||
def calculate_traffic(cleaned_subscriptions: list[str], expiry_time_ms: int | None) -> str:
|
||||
"""
|
||||
Рассчитывает информацию о трафике на основе подписок.
|
||||
@@ -294,7 +291,6 @@ def prepare_headers(
|
||||
}
|
||||
|
||||
|
||||
# Основные обработчики запросов
|
||||
async def handle_subscription(request: web.Request, old_subscription: bool = False) -> web.Response:
|
||||
"""
|
||||
Обрабатывает запрос на подписку (старую или новую).
|
||||
@@ -317,8 +313,8 @@ async def handle_subscription(request: web.Request, old_subscription: bool = Fal
|
||||
f"Обработка запроса для {'старого' if old_subscription else 'нового'} клиента: email={email}, tg_id={tg_id}"
|
||||
)
|
||||
|
||||
async with asyncpg.connect(DATABASE_URL) as conn:
|
||||
# Получение данных клиента
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
client_data = await get_key_details(email, conn)
|
||||
if not client_data:
|
||||
logger.warning(f"Клиент с email {email} не найден в базе.")
|
||||
@@ -327,19 +323,15 @@ async def handle_subscription(request: web.Request, old_subscription: bool = Fal
|
||||
stored_tg_id = client_data.get("tg_id")
|
||||
server_id = client_data["server_id"]
|
||||
|
||||
# Проверка tg_id для новых клиентов
|
||||
if not old_subscription and str(tg_id) != str(stored_tg_id):
|
||||
logger.warning(f"Неверный tg_id для клиента с email {email}.")
|
||||
return web.Response(text="❌ Неверные данные. Получите свой ключ в боте.", status=403)
|
||||
|
||||
# Проверка даты создания для старых клиентов
|
||||
if old_subscription:
|
||||
created_at_ms = client_data["created_at"]
|
||||
# Используем pytz для корректного сравнения времени
|
||||
created_at_datetime = datetime.utcfromtimestamp(created_at_ms / 1000)
|
||||
logger.info(f"created_at для {email}: {created_at_datetime}, server_id: {server_id}")
|
||||
|
||||
# Получаем временную метку перехода
|
||||
transition_timestamp_ms = get_transition_timestamp()
|
||||
logger.info(f"Время перехода (с учетом часового пояса Москвы): {transition_timestamp_ms}")
|
||||
|
||||
@@ -347,34 +339,30 @@ async def handle_subscription(request: web.Request, old_subscription: bool = Fal
|
||||
logger.info(f"Клиент с email {email} является новым.")
|
||||
return web.Response(text="❌ Эта ссылка устарела. Пожалуйста, обновите ссылку.", status=400)
|
||||
|
||||
# Форматирование оставшегося времени
|
||||
expiry_time_ms = client_data.get("expiry_time")
|
||||
time_left = format_time_left(expiry_time_ms)
|
||||
|
||||
# Получение URL-адресов подписки
|
||||
urls = await get_subscription_urls(server_id, email, conn)
|
||||
if not urls:
|
||||
return web.Response(text="❌ Сервер не найден.", status=404)
|
||||
|
||||
# Получение и обработка подписок
|
||||
query_string = request.query_string if not old_subscription else ""
|
||||
combined_subscriptions = await combine_unique_lines(urls, tg_id or email, query_string)
|
||||
random.shuffle(combined_subscriptions)
|
||||
|
||||
# Очистка строк подписки
|
||||
cleaned_subscriptions = [clean_subscription_line(line) for line in combined_subscriptions]
|
||||
|
||||
# Кодирование подписки в base64
|
||||
base64_encoded = base64.b64encode("\n".join(cleaned_subscriptions).encode("utf-8")).decode("utf-8")
|
||||
subscription_info = f"📄 Подписка: {email} - {time_left}"
|
||||
|
||||
# Подготовка заголовков ответа
|
||||
user_agent = request.headers.get("User-Agent", "")
|
||||
subscription_userinfo = calculate_traffic(cleaned_subscriptions, expiry_time_ms)
|
||||
headers = prepare_headers(user_agent, PROJECT_NAME, subscription_info, subscription_userinfo)
|
||||
|
||||
logger.info(f"Возвращаем объединенные подписки для email: {email}")
|
||||
return web.Response(text=base64_encoded, headers=headers)
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
|
||||
async def handle_old_subscription(request: web.Request) -> web.Response:
|
||||
|
||||
@@ -4,6 +4,7 @@ from datetime import datetime, timedelta
|
||||
import asyncpg
|
||||
import pytz
|
||||
from aiogram import Bot, Router
|
||||
|
||||
from config import (
|
||||
DATABASE_URL,
|
||||
NOTIFICATION_TIME,
|
||||
@@ -16,7 +17,6 @@ from config import (
|
||||
TOTAL_GB,
|
||||
TRIAL_TIME_DISABLE,
|
||||
)
|
||||
|
||||
from database import (
|
||||
add_notification,
|
||||
check_notification_time,
|
||||
|
||||
@@ -6,8 +6,8 @@ import pytz
|
||||
from aiogram import Bot, Router, types
|
||||
from aiogram.exceptions import TelegramForbiddenError
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from config import NOTIFY_EXTRA_DAYS, NOTIFY_INACTIVE, NOTIFY_INACTIVE_TRAFFIC, SUPPORT_CHAT_URL, TRIAL_TIME
|
||||
|
||||
from config import NOTIFY_EXTRA_DAYS, NOTIFY_INACTIVE, NOTIFY_INACTIVE_TRAFFIC, SUPPORT_CHAT_URL, TRIAL_TIME
|
||||
from database import (
|
||||
add_notification,
|
||||
check_notification_time,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from aiogram import F, Router
|
||||
from aiogram.types import CallbackQuery, InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from config import (
|
||||
CRYPTO_BOT_ENABLE,
|
||||
DONATIONS_ENABLE,
|
||||
|
||||
+851
-878
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -99,12 +99,13 @@ async def process_callback_pay_robokassa(callback_query: types.CallbackQuery, st
|
||||
await add_connection(tg_id, balance=0.0, trial=0, session=session)
|
||||
logger.info(f"Created new connection for user {tg_id} with balance 0.0.")
|
||||
|
||||
await edit_or_send_message(
|
||||
target_message=callback_query.message,
|
||||
await callback_query.message.delete()
|
||||
|
||||
new_message = await callback_query.message.answer(
|
||||
text="Выберите сумму пополнения:",
|
||||
reply_markup=builder.as_markup(),
|
||||
force_text=True,
|
||||
)
|
||||
await state.update_data(message_id=new_message.message_id, chat_id=new_message.chat.id)
|
||||
await state.set_state(ReplenishBalanceState.choosing_amount_robokassa)
|
||||
logger.info(f"Displayed amount selection for user {tg_id}.")
|
||||
|
||||
|
||||
+1
-1
@@ -14,6 +14,7 @@ from aiogram.types import (
|
||||
Message,
|
||||
)
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from config import (
|
||||
DATABASE_URL,
|
||||
INLINE_MODE,
|
||||
@@ -24,7 +25,6 @@ from config import (
|
||||
TRIAL_TIME,
|
||||
USERNAME_BOT,
|
||||
)
|
||||
|
||||
from database import get_balance, get_key_count, get_last_payments, get_referral_stats, get_trial
|
||||
from handlers.buttons.profile import (
|
||||
ADD_SUB,
|
||||
|
||||
+8
-2
@@ -10,6 +10,8 @@ from aiogram.types import (
|
||||
Message,
|
||||
)
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from bot import bot
|
||||
from config import (
|
||||
CAPTCHA_ENABLE,
|
||||
CHANNEL_EXISTS,
|
||||
@@ -19,8 +21,6 @@ from config import (
|
||||
DONATIONS_ENABLE,
|
||||
SUPPORT_CHAT_URL,
|
||||
)
|
||||
|
||||
from bot import bot
|
||||
from database import (
|
||||
add_connection,
|
||||
add_referral,
|
||||
@@ -265,6 +265,12 @@ async def process_start_logic(
|
||||
await add_referral(message.chat.id, referrer_tg_id, session)
|
||||
logger.info(f"Реферал {message.chat.id} использовал ссылку от пользователя {referrer_tg_id}")
|
||||
await message.answer(f"Вы стали рефералом пользователя с ID {referrer_tg_id}")
|
||||
try:
|
||||
await bot.send_message(referrer_tg_id, f"🎉 Ваш реферал {message.chat.id} успешно зарегистрировался!")
|
||||
logger.info(f"Уведомление отправлено пользователю {referrer_tg_id} о новом реферале {message.chat.id}")
|
||||
except Exception as e:
|
||||
logger.error(f"Не удалось отправить уведомление пригласившему ({referrer_tg_id}): {e}")
|
||||
|
||||
return await show_start_menu(message, admin, session)
|
||||
|
||||
except (ValueError, IndexError) as e:
|
||||
|
||||
+1
-1
@@ -8,9 +8,9 @@ import aiofiles
|
||||
import aiohttp
|
||||
import asyncpg
|
||||
from aiogram.types import BufferedInputFile, InlineKeyboardMarkup, InputMediaPhoto, Message
|
||||
from config import DATABASE_URL
|
||||
|
||||
from bot import bot
|
||||
from config import DATABASE_URL
|
||||
from database import get_all_keys, get_servers
|
||||
from logger import logger
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ from datetime import datetime, timezone
|
||||
from aiogram.filters.callback_data import CallbackData
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from config import RENEWAL_PRICES
|
||||
|
||||
from config import RENEWAL_PRICES
|
||||
from keyboards.admin.panel_kb import build_admin_back_btn
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import Any, Dict, Set, cast
|
||||
|
||||
from aiogram import BaseMiddleware
|
||||
from aiogram.types import CallbackQuery, Message, TelegramObject
|
||||
|
||||
from config import ADMIN_ID
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import Any, Optional
|
||||
import asyncpg
|
||||
from aiogram import BaseMiddleware
|
||||
from aiogram.types import TelegramObject
|
||||
|
||||
from config import DATABASE_URL
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -4,10 +4,10 @@ from datetime import datetime, timedelta
|
||||
|
||||
from aiogram.types import InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from config import ADMIN_ID, DATABASE_URL, PING_TIME
|
||||
from ping3 import ping
|
||||
|
||||
from bot import bot
|
||||
from config import ADMIN_ID, PING_TIME
|
||||
from database import get_servers
|
||||
from keyboards.admin.servers_kb import AdminServerEditorCallback
|
||||
from logger import logger
|
||||
|
||||
Reference in New Issue
Block a user