124 lines
5.0 KiB
Python
124 lines
5.0 KiB
Python
import asyncio
|
|
import aiosqlite
|
|
from datetime import datetime
|
|
from logging import getLogger
|
|
from aiogram import Dispatcher, Bot
|
|
from config import Config
|
|
from models.state import BotState
|
|
from utils.antispam import save_message
|
|
|
|
logger = getLogger(__name__)
|
|
|
|
|
|
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot) -> int:
|
|
async def init_db():
|
|
if Config.DISABLE_STORAGE:
|
|
return
|
|
async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db:
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS days_to_new_year (
|
|
user_id INTEGER PRIMARY KEY,
|
|
days INTEGER NOT NULL,
|
|
timestamp TEXT NOT NULL
|
|
)
|
|
""")
|
|
await db.commit()
|
|
logger.info("База данных инициализирована")
|
|
|
|
async def save_days_to_db(user_id: int, days: int):
|
|
if Config.DISABLE_STORAGE:
|
|
return
|
|
logger.debug(f"Сохраняем user_id={user_id}, days={days}")
|
|
async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db:
|
|
await db.execute("""
|
|
INSERT OR REPLACE INTO days_to_new_year (user_id, days, timestamp)
|
|
VALUES (?, ?, ?)
|
|
""", (int(user_id), int(days), datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
|
|
await db.commit()
|
|
logger.info(f"Запись сохранена: user_id={user_id}, days={days}")
|
|
|
|
async def get_last_days(user_id: int) -> int | None:
|
|
if Config.DISABLE_STORAGE:
|
|
return None
|
|
async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db:
|
|
async with db.execute(
|
|
"SELECT days FROM days_to_new_year WHERE user_id = ?", (int(user_id),)
|
|
) as cursor:
|
|
row = await cursor.fetchone()
|
|
return row[0] if row else None
|
|
|
|
async def days_to_new_years() -> int:
|
|
now = datetime.now()
|
|
new_year = datetime(now.year + 1, 1, 1)
|
|
delta = (new_year - now).days
|
|
logger.debug(f"До Нового года осталось {delta} дней")
|
|
return delta
|
|
|
|
async def days_to_summer() -> int:
|
|
"""Считает дни до 1 июня текущего года (или следующего, если уже лето прошло)."""
|
|
now = datetime.now()
|
|
summer = datetime(now.year, 6, 1)
|
|
if now >= summer:
|
|
summer = datetime(now.year + 1, 6, 1)
|
|
delta = (summer - now).days
|
|
logger.debug(f"До лета осталось {delta} дней")
|
|
return delta
|
|
|
|
async def days_to_session() -> int:
|
|
"""Считает дни до 1 июня текущего года (или следующего, если уже лето прошло)."""
|
|
now = datetime.now()
|
|
summer = datetime(2026, 7, 6)
|
|
if now >= summer:
|
|
logger.warning("days_to_session")
|
|
delta = (summer - now).days
|
|
logger.debug(f"До Сессии осталось {delta} дней")
|
|
return delta
|
|
|
|
async def send_days_to_new_years(user_id: int):
|
|
days_ny = await days_to_new_years()
|
|
days_summer = await days_to_summer()
|
|
days_session = await days_to_session()
|
|
last_days = await get_last_days(user_id)
|
|
|
|
if last_days == days_ny:
|
|
logger.info(f"user_id={user_id}: запись уже есть ({days_ny} дней), пропускаем")
|
|
return
|
|
|
|
await save_days_to_db(user_id, days_ny)
|
|
|
|
events = [
|
|
("🌞 До лета", days_summer),
|
|
("📚 До конца сессии", days_session),
|
|
("🎄 До Нового года", days_ny),
|
|
]
|
|
|
|
# сортировка по числу дней (от меньшего к большему)
|
|
events_sorted = sorted(events, key=lambda x: x[1])
|
|
|
|
message_text = "\n".join([f"{emoji} осталось {days} дней!" for emoji, days in events_sorted])
|
|
|
|
|
|
for chat_id in Config.CHAT_IDS:
|
|
try:
|
|
logger.info(f"Отправляем сообщение в чат {chat_id} для user_id={user_id}")
|
|
await bot.send_message(chat_id, message_text)
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при отправке в чат {chat_id}: {e}")
|
|
|
|
async def periodic_task():
|
|
await init_db()
|
|
while True:
|
|
logger.info("Запуск цикла periodic_task")
|
|
for uid in Config.CHAT_IDS:
|
|
try:
|
|
msg = await send_days_to_new_years(int(uid))
|
|
if msg:
|
|
save_message(msg.chat.id, msg.message_id)
|
|
except Exception as e:
|
|
logger.exception(f"Ошибка при обработке uid={uid}: {e}")
|
|
logger.info("Завершён цикл periodic_task, спим 6 часов")
|
|
await asyncio.sleep(21600) # каждые 6 часов
|
|
|
|
asyncio.create_task(periodic_task())
|
|
return 0
|