fix_refferal/GIFTS/redirect/name_sub and more

This commit is contained in:
Vladless
2024-12-19 20:37:41 +03:00
parent 725167f663
commit c01b528055
49 changed files with 147036 additions and 1723 deletions
+99 -49
View File
@@ -2,8 +2,8 @@ from datetime import datetime
from typing import Any
import asyncpg
from config import DATABASE_URL, REFERRAL_BONUS_PERCENTAGES
from config import DATABASE_URL, REFERRAL_BONUS_PERCENTAGES
from logger import logger
@@ -11,7 +11,6 @@ async def init_db(file_path: str = "assets/schema.sql"):
with open(file_path) as file:
sql_content = file.read()
# Split the file content into individual SQL statements and connect to the database
statements = [stmt.strip() for stmt in sql_content.split(";") if stmt.strip()]
conn = await asyncpg.connect(DATABASE_URL)
@@ -92,7 +91,6 @@ async def get_all_coupons(session: Any):
Exception: В случае ошибки при получении данных из базы
"""
try:
# Выполняем запрос на получение всех купонов из базы данных
coupons = await session.fetch(
"""
SELECT code, amount, usage_limit, usage_count
@@ -100,12 +98,10 @@ async def get_all_coupons(session: Any):
"""
)
# Логируем успешное получение списка купонов
logger.info(f"Успешно получено {len(coupons)} купонов из базы данных")
return coupons
except Exception as e:
# Подробное логирование ошибки при получении купонов
logger.error(f"Критическая ошибка при получении списка купонов: {e}")
logger.exception("Трассировка стека ошибки получения купонов")
return []
@@ -129,7 +125,6 @@ async def delete_coupon_from_db(coupon_code: str, session: Any):
result = await delete_coupon_from_db('SALE50', session)
"""
try:
# Проверяем существование купона в базе данных
coupon_record = await session.fetchrow(
"""
SELECT id FROM coupons WHERE code = $1
@@ -137,12 +132,10 @@ async def delete_coupon_from_db(coupon_code: str, session: Any):
coupon_code,
)
# Если купон не найден, возвращаем False
if not coupon_record:
logger.info(f"Купон {coupon_code} не найден в базе данных")
return False
# Удаляем купон из базы данных
await session.execute(
"""
DELETE FROM coupons WHERE code = $1
@@ -150,12 +143,10 @@ async def delete_coupon_from_db(coupon_code: str, session: Any):
coupon_code,
)
# Логируем успешное удаление купона
logger.info(f"Купон {coupon_code} успешно удален из базы данных")
return True
except Exception as e:
# Логируем ошибку на русском с подробным описанием
logger.error(f"Произошла ошибка при удалении купона {coupon_code}: {e}")
return False
@@ -577,12 +568,11 @@ async def get_all_users(conn):
async def add_referral(referred_tg_id: int, referrer_tg_id: int, session: Any):
try:
# Если айди приглашенного совпадает с айди пригласившего
if referred_tg_id == referrer_tg_id:
logger.warning(f"Пользователь {referred_tg_id} попытался использовать свою собственную реферальную ссылку.")
return
# Вставка записи о реферале в базу данных
await session.execute(
"""
INSERT INTO referrals (referred_tg_id, referrer_tg_id)
@@ -619,7 +609,6 @@ async def handle_referral_on_balance_update(tg_id: int, amount: float):
logger.info(f"Начало обработки реферальной системы для пользователя {tg_id}")
MAX_REFERRAL_LEVELS = len(REFERRAL_BONUS_PERCENTAGES.keys())
visited_tg_ids = set()
current_tg_id = tg_id
@@ -644,11 +633,16 @@ async def handle_referral_on_balance_update(tg_id: int, amount: float):
)
if not referral:
logger.info(f"Цепочка рефералов завершена на уровне {level}.")
break
referrer_tg_id = referral["referrer_tg_id"]
referral_chain.append({"tg_id": referrer_tg_id, "level": level})
if referrer_tg_id in visited_tg_ids:
logger.warning(f"Реферер {referrer_tg_id} уже обработан. Пропуск.")
break
referral_chain.append({"tg_id": referrer_tg_id, "level": level})
current_tg_id = referrer_tg_id
for referral in referral_chain:
@@ -656,14 +650,16 @@ async def handle_referral_on_balance_update(tg_id: int, amount: float):
level = referral["level"]
bonus_percent = REFERRAL_BONUS_PERCENTAGES.get(level, 0)
bonus = amount * bonus_percent
bonus = max(bonus, 0)
if bonus_percent <= 0:
logger.warning(f"Процент бонуса для уровня {level} равен 0. Пропуск.")
continue
bonus = round(amount * bonus_percent, 2)
if bonus > 0:
logger.info(
f"Начисление бонуса {bonus} рублей рефереру {referrer_tg_id} на уровне {level}"
f"Начисление бонуса {bonus} рублей рефереру {referrer_tg_id} на уровне {level}."
)
await update_balance(referrer_tg_id, bonus)
except Exception as e:
@@ -676,22 +672,6 @@ async def handle_referral_on_balance_update(tg_id: int, amount: float):
async def get_referral_stats(referrer_tg_id: int):
"""
Получение подробной статистики рефералов для указанного пользователя.
Args:
referrer_tg_id (int): Telegram ID пользователя, для которого запрашивается статистика рефералов.
Returns:
dict: Словарь с детальной статистикой рефералов, содержащий:
- total_referrals (int): Общее количество рефералов
- active_referrals (int): Количество активных рефералов (с начисленным бонусом)
- referrals_by_level (dict): Количество рефералов по каждому уровню
- total_referral_bonus (float): Общая сумма бонусов от рефералов
Raises:
Exception: В случае ошибки при подключении к базе данных или выполнении запроса
"""
conn = None
try:
conn = await asyncpg.connect(DATABASE_URL)
@@ -699,25 +679,22 @@ async def get_referral_stats(referrer_tg_id: int):
f"Установлено подключение к базе данных для получения статистики рефералов пользователя {referrer_tg_id}"
)
# Общее количество рефералов
total_referrals = await conn.fetchval(
"""
SELECT COUNT(*) FROM referrals WHERE referrer_tg_id = $1
""",
""",
referrer_tg_id,
)
logger.debug(f"Получено общее количество рефералов: {total_referrals}")
# Активные рефералы
active_referrals = await conn.fetchval(
"""
SELECT COUNT(*) FROM referrals WHERE referrer_tg_id = $1 AND reward_issued = TRUE
""",
""",
referrer_tg_id,
)
logger.debug(f"Получено количество активных рефералов: {active_referrals}")
# Рефералы по уровням
referrals_by_level_records = await conn.fetch(
"""
WITH RECURSIVE referral_levels AS (
@@ -739,11 +716,10 @@ async def get_referral_stats(referrer_tg_id: int):
JOIN referrals r ON rl.referred_tg_id = r.referred_tg_id
GROUP BY level
ORDER BY level
""",
""",
referrer_tg_id,
)
# Преобразование результатов в словарь
referrals_by_level = {
record["level"]: {
"total": record["level_count"],
@@ -753,17 +729,37 @@ async def get_referral_stats(referrer_tg_id: int):
}
logger.debug(f"Получена статистика рефералов по уровням: {referrals_by_level}")
# Общая сумма бонусов от рефералов
total_referral_bonus = await conn.fetchval(
"""
SELECT COALESCE(SUM(amount), 0)
FROM payments
WHERE tg_id IN (
SELECT referred_tg_id
WITH RECURSIVE referral_levels AS (
SELECT
referred_tg_id,
referrer_tg_id,
1 AS level
FROM referrals
WHERE referrer_tg_id = $1
) AND status = 'success'
""",
UNION
SELECT
r.referred_tg_id,
r.referrer_tg_id,
rl.level + 1
FROM referrals r
JOIN referral_levels rl ON r.referrer_tg_id = rl.referred_tg_id
WHERE rl.level < 5
)
SELECT
SUM(p.amount * CASE
WHEN rl.level = 1 THEN 0.25
WHEN rl.level = 2 THEN 0.10
WHEN rl.level = 3 THEN 0.05
ELSE 0
END) AS total_bonus
FROM referral_levels rl
JOIN payments p ON rl.referred_tg_id = p.tg_id
WHERE p.status = 'success'
""",
referrer_tg_id,
)
logger.debug(
@@ -788,6 +784,7 @@ async def get_referral_stats(referrer_tg_id: int):
logger.info("Закрытие подключения к базе данных")
async def update_key_expiry(client_id: str, new_expiry_time: int):
"""
Обновление времени истечения ключа для указанного клиента.
@@ -1204,7 +1201,7 @@ async def get_servers_from_db():
async def delete_user_data(session: Any, tg_id: int):
try:
await session.execute("DELETE FROM gifts WHERE sender_tg_id = $1 OR recipient_tg_id = $1", tg_id)
except Exception as e:
@@ -1216,3 +1213,56 @@ async def delete_user_data(session: Any, tg_id: int):
await session.execute("DELETE FROM connections WHERE tg_id = $1", tg_id)
await session.execute("DELETE FROM keys WHERE tg_id = $1", tg_id)
await session.execute("DELETE FROM referrals WHERE referrer_tg_id = $1", tg_id)
async def store_gift_link(
gift_id: str, sender_tg_id: int, selected_months: int, expiry_time: datetime, gift_link: str, session: Any = None
):
"""
Добавляет информацию о подарке в базу данных.
Args:
gift_id (str): Уникальный идентификатор подарка
sender_tg_id (int): Идентификатор пользователя, который отправил подарок
selected_months (int): Количество месяцев подписки
expiry_time (datetime): Время окончания подписки
gift_link (str): Ссылка для активации подарка
session (Any): Сессия базы данных для выполнения запроса
Returns:
bool: True, если информация о подарке успешно добавлена, иначе False
Raises:
Exception: В случае ошибки при сохранении информации о подарке
"""
conn = None
try:
conn = session if session is not None else await asyncpg.connect(DATABASE_URL)
result = await conn.execute(
"""
INSERT INTO gifts (gift_id, sender_tg_id, recipient_tg_id, selected_months, expiry_time, gift_link, created_at, is_used)
VALUES ($1, $2, NULL, $3, $4, $5, $6, FALSE)
""",
gift_id,
sender_tg_id,
selected_months,
expiry_time,
gift_link,
datetime.utcnow(),
)
if result:
logger.info(f"Подарок с ID {gift_id} успешно добавлен в базу данных.")
return True
else:
logger.error(f"Не удалось добавить подарок с ID {gift_id} в базу данных.")
return False
except Exception as e:
logger.error(f"Ошибка при сохранении подарка с ID {gift_id} в базе данных: {e}")
return False
finally:
if conn is not None and session is None:
await conn.close()