diff --git a/database.py b/database.py index b50d1896..07c87fa9 100644 --- a/database.py +++ b/database.py @@ -52,6 +52,13 @@ async def init_db(): ''') except asyncpg.exceptions.DuplicateColumnError: pass + try: + await conn.execute(''' + ALTER TABLE keys + ADD COLUMN notified_24h BOOLEAN NOT NULL DEFAULT FALSE + ''') + except asyncpg.exceptions.DuplicateColumnError: + pass await conn.close() diff --git a/handlers/__pycache__/notifications.cpython-310.pyc b/handlers/__pycache__/notifications.cpython-310.pyc index f211f260..89fe99c3 100644 Binary files a/handlers/__pycache__/notifications.cpython-310.pyc and b/handlers/__pycache__/notifications.cpython-310.pyc differ diff --git a/handlers/notifications.py b/handlers/notifications.py index 8d829a29..c2257ced 100644 --- a/handlers/notifications.py +++ b/handlers/notifications.py @@ -1,11 +1,9 @@ from datetime import datetime, timedelta - import asyncpg from aiogram import Bot, Router, types from aiogram.filters import Command from aiogram.fsm.state import State, StatesGroup from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup - from auth import login_with_credentials from bot import bot from client import delete_client, extend_client_key @@ -21,57 +19,37 @@ async def notify_expiring_keys(bot: Bot): try: conn = await asyncpg.connect(DATABASE_URL) try: - # Напоминание за 10 часов - threshold_time_10h = (datetime.utcnow() + timedelta(hours=10)).timestamp() * 1000 - records_10h = await conn.fetch(''' + current_time = datetime.utcnow().timestamp() * 1000 + threshold_time_10h = (datetime.utcnow() + timedelta(hours=10)).timestamp() * 1000 + threshold_time_24h = (datetime.utcnow() + timedelta(days=1)).timestamp() * 1000 + + # Уведомления за 10 часов + records = await conn.fetch(''' SELECT tg_id, email, expiry_time, client_id, server_id FROM keys WHERE expiry_time <= $1 AND expiry_time > $2 AND notified = FALSE - ''', threshold_time_10h, datetime.utcnow().timestamp() * 1000) + ''', threshold_time_10h, current_time) - for record in records_10h: + for record in records: tg_id = record['tg_id'] email = record['email'] expiry_time = record['expiry_time'] server_id = record['server_id'] - time_left = (expiry_time / 1000) - datetime.utcnow().timestamp() - hours_left = max(0, int(time_left // 3600)) + # Логика формирования и отправки сообщения для уведомлений за 10 часов + message = f"🔔 Уведомление: Ваш ключ для сервера {server_id} истекает через 10 часов.\n" \ + f"Email: {email}\n" \ + f"Дата истечения: {datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S')}" + + await bot.send_message(tg_id, message) - expiry_date = datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S') - balance = await get_balance(tg_id) + # Обновление статуса уведомления + await conn.execute('UPDATE keys SET notified = TRUE WHERE client_id = $1', record['client_id']) - keyboard = InlineKeyboardMarkup(inline_keyboard=[ - [ - InlineKeyboardButton(text='1 месяц (100 руб.)', callback_data=f'renew_plan|1|{record["client_id"]}'), - InlineKeyboardButton(text='3 месяца (285 руб.)', callback_data=f'renew_plan|3|{record["client_id"]}') - ], - [ - InlineKeyboardButton(text='6 месяцев (540 руб.)', callback_data=f'renew_plan|6|{record["client_id"]}'), - InlineKeyboardButton(text='1 год (1000 руб.)', callback_data=f'renew_plan|12|{record["client_id"]}') - ], - [ - InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance'), - InlineKeyboardButton(text='Назад', callback_data='back_to_main') - ] - ]) - - message = (f"Ваш ключ {email} истечет и будет удален через {hours_left} часов " - f"({expiry_date}). Пожалуйста, продлите его.\n" - f"Ваш текущий баланс: {balance:.2f} руб.") - - try: - await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML', reply_markup=keyboard) - - await conn.execute('UPDATE keys SET notified = TRUE WHERE client_id = $1', record['client_id']) - except Exception as e: - print(f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя.") - - # Напоминание за 24 часа - threshold_time_24h = (datetime.utcnow() + timedelta(days=1)).timestamp() * 1000 + # Уведомления за 24 часа records_24h = await conn.fetch(''' SELECT tg_id, email, expiry_time, client_id, server_id FROM keys WHERE expiry_time <= $1 AND expiry_time > $2 AND notified_24h = FALSE - ''', threshold_time_24h, datetime.utcnow().timestamp() * 1000) + ''', threshold_time_24h, current_time) for record in records_24h: tg_id = record['tg_id'] @@ -83,86 +61,19 @@ async def notify_expiring_keys(bot: Bot): hours_left = max(0, int(time_left // 3600)) expiry_date = datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S') - balance = await get_balance(tg_id) - - keyboard = InlineKeyboardMarkup(inline_keyboard=[ - [ - InlineKeyboardButton(text='1 месяц (100 руб.)', callback_data=f'renew_plan|1|{record["client_id"]}'), - InlineKeyboardButton(text='3 месяца (285 руб.)', callback_data=f'renew_plan|3|{record["client_id"]}') - ], - [ - InlineKeyboardButton(text='6 месяцев (540 руб.)', callback_data=f'renew_plan|6|{record["client_id"]}'), - InlineKeyboardButton(text='1 год (1000 руб.)', callback_data=f'renew_plan|12|{record["client_id"]}') - ], - [ - InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance'), - InlineKeyboardButton(text='Назад', callback_data='back_to_main') - ] - ]) - - message = (f"Ваш ключ {email} истечет через {hours_left} часов " - f"({expiry_date}). Пожалуйста, продлите его.\n" - f"Ваш текущий баланс: {balance:.2f} руб.") - - try: - await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML', reply_markup=keyboard) - - await conn.execute('UPDATE keys SET notified_24h = TRUE WHERE client_id = $1', record['client_id']) - except Exception as e: - print(f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя.") - - # Обработка истекших ключей - expired_records = await conn.fetch(''' - SELECT tg_id, email, client_id, server_id FROM keys - WHERE expiry_time <= $1 - ''', datetime.utcnow().timestamp() * 1000) - - for record in expired_records: - tg_id = record['tg_id'] - email = record['email'] - client_id = record['client_id'] - server_id = record['server_id'] - balance = await get_balance(tg_id) - if balance >= 100: - # Продлеваем ключ на 1 месяц и списываем 100 рублей - new_expiry_time = datetime.utcnow() + timedelta(days=30) - await conn.execute(''' - UPDATE keys SET expiry_time = $1 WHERE client_id = $2 - ''', new_expiry_time.timestamp() * 1000, client_id) + # Логика формирования и отправки сообщения для уведомлений за 24 часа + message_24h = f"⏳ Уведомление: Ваш ключ для сервера {server_id} истекает через 24 часа.\n" \ + f"Email: {email}\n" \ + f"Осталось времени: {hours_left} часов\n" \ + f"Дата истечения: {expiry_date}\n" \ + f"Баланс: {balance:.2f} руб." - # Списываем 100 рублей с баланса - await update_balance(tg_id, -100) + await bot.send_message(tg_id, message_24h) - session = await login_with_credentials(server_id, ADMIN_USERNAME, ADMIN_PASSWORD) - await extend_client_key(session, server_id, client_id, 30) - - message = (f"Ваш ключ {email} был автоматически продлен на 1 месяц, так как у вас на балансе было достаточно средств. " - f"Новый срок истечения: {new_expiry_time.strftime('%Y-%m-%d %H:%M:%S')}.\n" - f"Ваш новый баланс: {balance - 100:.2f} руб.") - - try: - await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML') - except Exception as e: - print(f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя.") - else: - # Удаляем ключ, если баланс недостаточный - await conn.execute('DELETE FROM keys WHERE client_id = $1', client_id) - - session = await login_with_credentials(server_id, ADMIN_USERNAME, ADMIN_PASSWORD) - await delete_client(session, server_id, client_id) - - keyboard = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text='В профиль', callback_data='view_profile')] - ]) - - message = f"Ваш ключ {email} истек, и был удален." - - try: - await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML', reply_markup=keyboard) - except Exception as e: - print(f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя.") + # Обновление статуса уведомления за 24 часа + await conn.execute('UPDATE keys SET notified_24h = TRUE WHERE client_id = $1', record['client_id']) finally: await conn.close()