"""Scheduler for daily birthday notifications.""" import telebot from datetime import datetime from typing import Optional from apscheduler.schedulers.blocking import BlockingScheduler from apscheduler.triggers.cron import CronTrigger import pytz from database import get_db_session, User, Chat, UserChat from messages import format_birthday_greeting from config import Config def send_birthday_notifications(bot: telebot.TeleBot) -> None: """Send birthday notifications to all chats for users with birthday today.""" db = get_db_session() try: today = datetime.now().date() day = today.day month = today.month # Get all users with birthday today users_with_birthday = db.query(User).filter( User.birthday_day == day, User.birthday_month == month ).all() if not users_with_birthday: return # For each user, send greetings to all their chats for user in users_with_birthday: # Get all chats where user is a member user_chats = db.query(Chat).join(UserChat).filter( UserChat.user_id == user.user_id, Chat.bot_is_admin == True ).all() greeting = format_birthday_greeting(user.first_name, user.preference_theme) for chat in user_chats: try: # Check if user is still in chat member = bot.get_chat_member(chat.chat_id, user.user_id) if member.status not in ['left', 'kicked']: bot.send_message(chat.chat_id, greeting) except telebot.apihelper.ApiTelegramException as e: # Handle errors: user blocked bot, bot removed from chat, etc. if e.error_code == 403: # Bot was blocked or removed from chat # Update chat status chat.bot_is_admin = False db.commit() elif e.error_code == 400: # Invalid chat or user pass # Silently continue for other errors except Exception: # Other errors - continue pass finally: db.close() def setup_scheduler(bot: telebot.TeleBot) -> BlockingScheduler: """Setup and start the scheduler for daily birthday notifications.""" # Parse notification time time_str: str = Config.NOTIFICATION_TIME try: hour, minute = map(int, time_str.split(':')) except (ValueError, AttributeError): hour, minute = 9, 0 # Default to 9:00 # Get timezone timezone_str: str = Config.TIMEZONE try: tz = pytz.timezone(timezone_str) except (pytz.exceptions.UnknownTimeZoneError, AttributeError): tz = pytz.UTC # Create scheduler scheduler = BlockingScheduler(timezone=tz) # Add daily job scheduler.add_job( send_birthday_notifications, trigger=CronTrigger(hour=hour, minute=minute), args=[bot], id='daily_birthday_notifications', name='Send daily birthday notifications', replace_existing=True ) return scheduler