Files
Solo_bot/handlers/notifications/special_notifications.py
T
2025-05-24 19:30:23 +03:00

192 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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("✅ Обработка пользователей с нулевым трафиком завершена.")