192 lines
6.8 KiB
Python
192 lines
6.8 KiB
Python
from datetime import datetime, timedelta
|
||
|
||
import pytz
|
||
from aiogram import Bot, Router, types
|
||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from config import (
|
||
NOTIFY_EXTRA_DAYS,
|
||
NOTIFY_INACTIVE,
|
||
NOTIFY_INACTIVE_TRAFFIC,
|
||
SUPPORT_CHAT_URL,
|
||
TRIAL_TIME,
|
||
)
|
||
from database import (
|
||
add_notification,
|
||
check_notifications_bulk,
|
||
mark_trial_extended,
|
||
update_key_notified,
|
||
)
|
||
from handlers.buttons import MAIN_MENU
|
||
from handlers.keys.key_utils import get_user_traffic
|
||
from handlers.texts import (
|
||
TRIAL_INACTIVE_BONUS_MSG,
|
||
TRIAL_INACTIVE_FIRST_MSG,
|
||
ZERO_TRAFFIC_MSG,
|
||
)
|
||
from handlers.utils import format_days
|
||
from logger import logger
|
||
|
||
from .notify_utils import send_messages_with_limit
|
||
|
||
router = Router()
|
||
moscow_tz = pytz.timezone("Europe/Moscow")
|
||
|
||
|
||
async def notify_inactive_trial_users(bot: Bot, session: AsyncSession):
|
||
logger.info("Проверка пользователей, не активировавших пробный период...")
|
||
users = await check_notifications_bulk(session, "inactive_trial", NOTIFY_INACTIVE)
|
||
logger.info(f"Найдено {len(users)} неактивных пользователей для уведомления.")
|
||
messages = []
|
||
|
||
for user in users:
|
||
tg_id = user["tg_id"]
|
||
username = user["username"]
|
||
first_name = user["first_name"]
|
||
last_name = user["last_name"]
|
||
display_name = username or first_name or last_name or "Пользователь"
|
||
|
||
builder = InlineKeyboardBuilder()
|
||
builder.row(
|
||
types.InlineKeyboardButton(
|
||
text="🚀 Активировать пробный период", callback_data="create_key"
|
||
)
|
||
)
|
||
builder.row(types.InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
|
||
keyboard = builder.as_markup()
|
||
|
||
trial_extended = user["last_notification_time"] is not None
|
||
|
||
if trial_extended:
|
||
total_days = NOTIFY_EXTRA_DAYS + TRIAL_TIME
|
||
message = TRIAL_INACTIVE_BONUS_MSG.format(
|
||
display_name=display_name,
|
||
extra_days_formatted=format_days(NOTIFY_EXTRA_DAYS),
|
||
total_days_formatted=format_days(total_days),
|
||
)
|
||
await mark_trial_extended(tg_id, session)
|
||
else:
|
||
message = TRIAL_INACTIVE_FIRST_MSG.format(
|
||
display_name=display_name, trial_time_formatted=format_days(TRIAL_TIME)
|
||
)
|
||
|
||
messages.append(
|
||
{
|
||
"tg_id": tg_id,
|
||
"text": message,
|
||
"keyboard": keyboard,
|
||
"notification_id": "inactive_trial",
|
||
}
|
||
)
|
||
|
||
if messages:
|
||
results = await send_messages_with_limit(
|
||
bot,
|
||
messages,
|
||
session=session,
|
||
source_file="special_notifications",
|
||
messages_per_second=25,
|
||
)
|
||
sent_count = 0
|
||
for msg, result in zip(messages, results, strict=False):
|
||
if result:
|
||
await add_notification(session, msg["tg_id"], msg["notification_id"])
|
||
sent_count += 1
|
||
logger.info(f"Отправлено {sent_count} уведомлений неактивным пользователям.")
|
||
logger.info("✅ Проверка пользователей с неактивным пробным периодом завершена.")
|
||
|
||
|
||
async def notify_users_no_traffic(
|
||
bot: Bot, session: AsyncSession, current_time: int, keys: list
|
||
):
|
||
logger.info("Проверка пользователей с нулевым трафиком...")
|
||
current_dt = datetime.fromtimestamp(current_time / 1000, tz=moscow_tz)
|
||
messages = []
|
||
|
||
for key in keys:
|
||
tg_id = key.tg_id
|
||
email = key.email
|
||
created_at = key.created_at
|
||
client_id = key.client_id
|
||
expiry_time = key.expiry_time
|
||
notified = key.notified
|
||
|
||
if created_at is None or notified:
|
||
continue
|
||
|
||
created_at_dt = pytz.utc.localize(
|
||
datetime.fromtimestamp(created_at / 1000)
|
||
).astimezone(moscow_tz)
|
||
if current_dt < created_at_dt + timedelta(hours=NOTIFY_INACTIVE_TRAFFIC):
|
||
continue
|
||
|
||
if expiry_time:
|
||
expiry_dt = pytz.utc.localize(
|
||
datetime.fromtimestamp(expiry_time / 1000)
|
||
).astimezone(moscow_tz)
|
||
if (current_dt - (expiry_dt - timedelta(days=30))) < timedelta(
|
||
hours=NOTIFY_INACTIVE_TRAFFIC
|
||
):
|
||
continue
|
||
|
||
try:
|
||
traffic_data = await get_user_traffic(session, tg_id, email)
|
||
except Exception as e:
|
||
logger.error(f"Ошибка получения трафика для {email}: {e}")
|
||
continue
|
||
|
||
if traffic_data.get("status") != "success":
|
||
logger.warning(
|
||
f"⚠ Ошибка при получении трафика для {email}: {traffic_data.get('message')}"
|
||
)
|
||
continue
|
||
|
||
total_traffic = sum(
|
||
value if isinstance(value, int | float) else 0
|
||
for value in traffic_data.get("traffic", {}).values()
|
||
)
|
||
|
||
try:
|
||
await update_key_notified(session, tg_id, client_id)
|
||
except Exception as e:
|
||
logger.error(f"Ошибка обновления notified для {tg_id} ({client_id}): {e}")
|
||
continue
|
||
|
||
if total_traffic == 0:
|
||
logger.info(
|
||
f"⚠ У пользователя {tg_id} ({email}) 0 ГБ трафика. Отправляем уведомление."
|
||
)
|
||
builder = InlineKeyboardBuilder()
|
||
builder.row(
|
||
types.InlineKeyboardButton(
|
||
text="🔧 Написать в поддержку", url=SUPPORT_CHAT_URL
|
||
)
|
||
)
|
||
builder.row(
|
||
types.InlineKeyboardButton(text=MAIN_MENU, callback_data="profile")
|
||
)
|
||
keyboard = builder.as_markup()
|
||
message = ZERO_TRAFFIC_MSG.format(email=email)
|
||
messages.append(
|
||
{
|
||
"tg_id": tg_id,
|
||
"text": message,
|
||
"keyboard": keyboard,
|
||
"client_id": client_id,
|
||
}
|
||
)
|
||
|
||
if messages:
|
||
results = await send_messages_with_limit(
|
||
bot,
|
||
messages,
|
||
session=session,
|
||
source_file="special_notifications",
|
||
messages_per_second=25,
|
||
)
|
||
sent_count = sum(result for result in results if result)
|
||
logger.info(f"Отправлено {sent_count} уведомлений о нулевом трафике.")
|
||
|
||
logger.info("✅ Обработка пользователей с нулевым трафиком завершена.")
|