From b2dbdb60b6606186bc45cbb767e41266ca216975 Mon Sep 17 00:00:00 2001 From: Capybara-z Date: Mon, 5 May 2025 21:38:11 +0300 Subject: [PATCH] Update notification --- .../notifications/general_notifications.py | 107 +++++++++++++----- 1 file changed, 77 insertions(+), 30 deletions(-) diff --git a/handlers/notifications/general_notifications.py b/handlers/notifications/general_notifications.py index 4c26d80a..d6951065 100644 --- a/handlers/notifications/general_notifications.py +++ b/handlers/notifications/general_notifications.py @@ -1,11 +1,8 @@ import asyncio - from datetime import datetime, timedelta - import asyncpg -import pytz - from aiogram import Bot, Router +import pytz from config import ( DATABASE_URL, @@ -33,7 +30,10 @@ from database import ( update_key_expiry, ) from handlers.keys.key_utils import delete_key_from_cluster, renew_key_in_cluster -from handlers.notifications.notify_kb import build_notification_expired_kb, build_notification_kb +from handlers.notifications.notify_kb import ( + build_notification_expired_kb, + build_notification_kb, +) from handlers.texts import ( KEY_DELETED_MSG, KEY_EXPIRED_DELAY_HOURS_MINUTES_MSG, @@ -47,17 +47,13 @@ from handlers.texts import ( ) from handlers.utils import format_hours, format_minutes from logger import logger -from handlers.utils import format_hours, format_months, format_minutes from .notify_utils import send_messages_with_limit, send_notification from .special_notifications import notify_inactive_trial_users, notify_users_no_traffic router = Router() - moscow_tz = pytz.timezone("Europe/Moscow") - - notification_lock = asyncio.Lock() @@ -77,7 +73,6 @@ async def periodic_notifications(bot: Bot): try: conn = await asyncpg.connect(DATABASE_URL) current_time = int(datetime.now(moscow_tz).timestamp() * 1000) - threshold_time_10h = int((datetime.now(moscow_tz) + timedelta(hours=10)).timestamp() * 1000) threshold_time_24h = int((datetime.now(moscow_tz) + timedelta(days=1)).timestamp() * 1000) @@ -91,17 +86,35 @@ async def periodic_notifications(bot: Bot): keys = [] if not TRIAL_TIME_DISABLE: - await notify_inactive_trial_users(bot, conn) + try: + await notify_inactive_trial_users(bot, conn) + except Exception as e: + logger.error(f"Ошибка в notify_inactive_trial_users: {e}") await asyncio.sleep(0.5) - await notify_24h_keys(bot, conn, current_time, threshold_time_24h, keys) + try: + await notify_24h_keys(bot, conn, current_time, threshold_time_24h, keys) + except Exception as e: + logger.error(f"Ошибка в notify_24h_keys: {e}") await asyncio.sleep(1) - await notify_10h_keys(bot, conn, current_time, threshold_time_10h, keys) + + try: + await notify_10h_keys(bot, conn, current_time, threshold_time_10h, keys) + except Exception as e: + logger.error(f"Ошибка в notify_10h_keys: {e}") await asyncio.sleep(1) - await handle_expired_keys(bot, conn, current_time, keys) + + try: + await handle_expired_keys(bot, conn, current_time, keys) + except Exception as e: + logger.error(f"Ошибка в handle_expired_keys: {e}") await asyncio.sleep(0.5) + if NOTIFY_INACTIVE_TRAFFIC: - await notify_users_no_traffic(bot, conn, current_time, keys) + try: + await notify_users_no_traffic(bot, conn, current_time, keys) + except Exception as e: + logger.error(f"Ошибка в notify_users_no_traffic: {e}") await asyncio.sleep(0.5) logger.info("Завершена обработка уведомлений") @@ -162,7 +175,11 @@ async def notify_24h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, ) if NOTIFY_RENEW: - await process_auto_renew_or_notify(bot, conn, key, notification_id, 1, "notify_24h.jpg", notification_text) + try: + await process_auto_renew_or_notify(bot, conn, key, notification_id, 1, "notify_24h.jpg", notification_text) + except Exception as e: + logger.error(f"Ошибка авто-продления/уведомления для пользователя {tg_id}: {e}") + continue else: keyboard = build_notification_kb(email) messages.append({ @@ -170,12 +187,21 @@ async def notify_24h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, "text": notification_text, "photo": "notify_24h.jpg", "keyboard": keyboard, + "notification_id": notification_id, }) - await add_notification(tg_id, notification_id, session=conn) if messages: - await send_messages_with_limit(bot, messages) - logger.info(f"Отправлено {len(messages)} уведомлений об истечении подписки через 24 часа.") + results = await send_messages_with_limit(bot, messages, conn=conn) + 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"📢 Отправлено уведомление об истекающей подписке {msg['email']} пользователю {tg_id}.") + else: + logger.warning(f"📢 Не удалось отправить уведомление об истекающей подписке {msg['email']} пользователю {tg_id}.") + logger.info(f"Отправлено {sent_count} уведомлений об истечении подписки через 24 часа.") logger.info("Обработка всех уведомлений за 24 часа завершена.") await asyncio.sleep(1) @@ -233,6 +259,7 @@ async def notify_10h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, ) except Exception as e: logger.error(f"Ошибка авто-продления/уведомления для пользователя {tg_id}: {e}") + continue else: keyboard = build_notification_kb(email) messages.append({ @@ -240,12 +267,21 @@ async def notify_10h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, "text": notification_text, "photo": "notify_10h.jpg", "keyboard": keyboard, + "notification_id": notification_id, }) - await add_notification(tg_id, notification_id, session=conn) if messages: - await send_messages_with_limit(bot, messages) - logger.info(f"Отправлено {len(messages)} уведомлений об истечении подписки через 10 часов.") + results = await send_messages_with_limit(bot, messages, conn=conn) + 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"📢 Отправлено уведомление об истекающей подписке {msg['email']} пользователю {tg_id}.") + else: + logger.warning(f"📢 Не удалось отправить уведомление об истекающей подписке {msg['email']} пользователю {tg_id}.") + logger.info(f"Отправлено {sent_count} уведомлений об истечении подписки через 10 часов.") logger.info("Обработка всех уведомлений за 10 часов завершена.") await asyncio.sleep(1) @@ -317,6 +353,8 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time: "text": KEY_DELETED_MSG.format(email=email), "photo": "notify_expired.jpg", "keyboard": keyboard, + "notification_id": notification_id, + "email": email, }) except Exception as e: logger.error(f"Ошибка удаления ключа {client_id} для пользователя {tg_id}: {e}") @@ -350,12 +388,23 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time: "text": delay_message, "photo": "notify_expired.jpg", "keyboard": keyboard, + "notification_id": notification_id, + "email": email, }) - await add_notification(tg_id, notification_id, session=conn) if messages: - await send_messages_with_limit(bot, messages) - logger.info(f"Отправлено {len(messages)} уведомлений об истекших ключах.") + results = await send_messages_with_limit(bot, messages, conn=conn) + sent_count = 0 + for msg, result in zip(messages, results): + tg_id = msg["tg_id"] + email = msg["email"] + if result: + await add_notification(tg_id, msg["notification_id"], session=conn) + sent_count += 1 + logger.info(f"📢 Отправлено уведомление об истекшем ключе для подписки {email} пользователю {tg_id}.") + else: + logger.warning(f"📢 Не удалось отправить уведомление об истекшем ключе для подписки {email} пользователю {tg_id}.") + logger.info(f"Отправлено {sent_count} уведомлений об истекших ключах.") logger.info("Обработка истекших ключей завершена.") await asyncio.sleep(1) @@ -404,7 +453,7 @@ async def process_auto_renew_or_notify( total_gb = int(renewal_period_months * TOTAL_GB * 1024**3) logger.info( - f"[Автопродление] Продление подписки {email} на {renewal_period_months} мес. для пользователя {tg_id}. Баланс: {balance}, списываем: {renewal_cost}" + f"Продление подписки {email} на {renewal_period_months} мес. для пользователя {tg_id}. Баланс: {balance}, списываем: {renewal_cost}" ) try: @@ -420,9 +469,7 @@ async def process_auto_renew_or_notify( ) renewed_message = KEY_RENEWED.format( - email=email, - months_formatted=months_formatted, - expiry_date=formatted_expiry_date + email=email, months=renewal_period_months, expiry_date=formatted_expiry_date ) keyboard = build_notification_expired_kb() @@ -439,9 +486,9 @@ async def process_auto_renew_or_notify( logger.error(f"❌ Ошибка при продлении ключа {client_id} для пользователя {tg_id}: {e}") else: keyboard = build_notification_kb(email) + await add_notification(tg_id, notification_id, session=conn) result = await send_notification(bot, tg_id, standard_photo, standard_caption, keyboard) if result: logger.info(f"📢 Отправлено уведомление об истекающей подписке {email} пользователю {tg_id}.") - await add_notification(tg_id, notification_id, session=conn) else: logger.warning(f"📢 Не удалось отправить уведомление об истекающей подписке {email} пользователю {tg_id}.")