From d3c729cdc2d871fce15b74c1f35d794b918cfe94 Mon Sep 17 00:00:00 2001 From: Capybara-z Date: Mon, 5 May 2025 21:40:06 +0300 Subject: [PATCH] Update notification --- .../notifications/special_notifications.py | 128 ++++++++++-------- 1 file changed, 68 insertions(+), 60 deletions(-) diff --git a/handlers/notifications/special_notifications.py b/handlers/notifications/special_notifications.py index d58a13e4..9f806027 100644 --- a/handlers/notifications/special_notifications.py +++ b/handlers/notifications/special_notifications.py @@ -1,32 +1,32 @@ import asyncio - from datetime import datetime, timedelta import asyncpg 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 database import ( - add_notification, - check_notifications_bulk, - create_blocked_user, +from config import ( + NOTIFY_EXTRA_DAYS, + NOTIFY_INACTIVE, + NOTIFY_INACTIVE_TRAFFIC, + SUPPORT_CHAT_URL, + TRIAL_TIME, ) +from database import add_notification, check_notifications_bulk, create_blocked_user 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.texts import ( + TRIAL_INACTIVE_BONUS_MSG, + TRIAL_INACTIVE_FIRST_MSG, + ZERO_TRAFFIC_MSG, +) from handlers.utils import format_days from logger import logger -from handlers.utils import format_days - from .notify_utils import send_messages_with_limit, send_notification router = Router() - moscow_tz = pytz.timezone("Europe/Moscow") @@ -37,19 +37,15 @@ async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection): Если прошло 24 часа и триал не активирован, отправляется уведомление с бонусом +2 дня. """ logger.info("Проверка пользователей, не активировавших пробный период...") - users = await check_notifications_bulk("inactive_trial", NOTIFY_INACTIVE, conn) 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( @@ -59,9 +55,7 @@ async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection): ) 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( @@ -74,21 +68,30 @@ async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection): message = TRIAL_INACTIVE_FIRST_MSG.format( display_name=display_name, trial_time_formatted=format_days(TRIAL_TIME) ) - - 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) - - except TelegramForbiddenError: - logger.warning(f"🚫 Бот заблокирован пользователем {tg_id}. Добавляем в blocked_users.") - await create_blocked_user(tg_id, conn) - - except Exception as e: - logger.error(f"⚠ Ошибка при отправке уведомления пользователю {tg_id}: {e}") - - await asyncio.sleep(1) - + messages.append({ + "tg_id": tg_id, + "text": message, + "keyboard": keyboard, + "notification_id": "inactive_trial", + }) + if messages: + results = await send_messages_with_limit( + bot, + messages, + conn=conn, + source_file="special_notifications", + messages_per_second=25 + ) + sent_count = 0 + for msg, result in zip(messages, results): + tg_id = msg["tg_id"] + if result: + await add_notification(tg_id, msg["notification_id"], session=conn) + sent_count += 1 + logger.info(f"📩 Отправлено уведомление неактивному пользователю {tg_id}.") + else: + logger.warning(f"📩 Не удалось отправить уведомление неактивному пользователю {tg_id}.") + logger.info(f"Отправлено {sent_count} уведомлений неактивным пользователям.") logger.info("✅ Проверка пользователей с неактивным пробным периодом завершена.") @@ -99,8 +102,8 @@ async def notify_users_no_traffic(bot: Bot, conn: asyncpg.Connection, current_ti но исключает пользователей, у которых подписка недавно продлилась. """ logger.info("Проверка пользователей с нулевым трафиком...") - current_dt = datetime.fromtimestamp(current_time / 1000, tz=moscow_tz) + messages = [] for key in keys: tg_id = key.get("tg_id") @@ -124,7 +127,6 @@ async def notify_users_no_traffic(bot: Bot, conn: asyncpg.Connection, current_ti expiry_dt = pytz.utc.localize(datetime.fromtimestamp(expiry_time / 1000)).astimezone(moscow_tz) renewal_threshold = expiry_dt - timedelta(days=30) renewal_recent = current_dt - renewal_threshold < timedelta(hours=NOTIFY_INACTIVE_TRAFFIC) - if renewal_recent: continue @@ -144,39 +146,45 @@ async def notify_users_no_traffic(bot: Bot, conn: asyncpg.Connection, current_ti total_traffic = sum( value if isinstance(value, int | float) else 0 for value in traffic_data.get("traffic", {}).values() ) - logger.info(f"Ключ для {email}: общий трафик: {total_traffic} ГБ") + + try: + await conn.execute( + "UPDATE keys SET notified = TRUE WHERE tg_id = $1 AND client_id = $2", tg_id, client_id + ) + except Exception as e: + logger.error(f"Ошибка обновления notified для пользователя {tg_id} (client_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, + }) - try: - result = await send_notification(bot, tg_id, None, message, keyboard) - await conn.execute( - "UPDATE keys SET notified = TRUE WHERE tg_id = $1 AND client_id = $2", tg_id, client_id - ) - if result: - logger.info(f"📩 Отправлено уведомление пользователю {tg_id} о нулевом трафике.") - else: - logger.warning(f"📩 Не удалось отправить уведомление пользователю {tg_id} о нулевом трафике.") - except TelegramForbiddenError: - logger.warning(f"🚫 Бот заблокирован пользователем {tg_id}.") - await create_blocked_user(tg_id, conn) - except Exception as e: - logger.error(f"⚠ Ошибка при отправке уведомления пользователю {tg_id}: {e}") - else: - try: - await conn.execute( - "UPDATE keys SET notified = TRUE WHERE tg_id = $1 AND client_id = $2", tg_id, client_id - ) - logger.info(f"Ключ для {email} имеет трафик. Обновлено notified = TRUE.") - except Exception as e: - logger.error(f"Ошибка обновления notified для пользователя {tg_id}: {e}") + if messages: + results = await send_messages_with_limit( + bot, + messages, + conn=conn, + source_file="special_notifications", + messages_per_second=25 + ) + sent_count = 0 + for msg, result in zip(messages, results): + tg_id = msg["tg_id"] + if result: + sent_count += 1 + logger.info(f"📩 Отправлено уведомление пользователю {tg_id} о нулевом трафике.") + else: + logger.warning(f"📩 Не удалось отправить уведомление пользователю {tg_id} о нулевом трафике.") + logger.info(f"Отправлено {sent_count} уведомлений о нулевом трафике.") logger.info("✅ Обработка пользователей с нулевым трафиком завершена.")