"""Handlers for group commands.""" import telebot from datetime import datetime, timedelta, date from typing import Dict, List from sqlalchemy.orm import Session from database import get_db_session, User, Chat, UserChat from collections import defaultdict def register_command_handlers(bot: telebot.TeleBot) -> None: """Register all command handlers.""" @bot.message_handler(commands=['stats'], chat_types=['group', 'supergroup']) def handle_stats(message: telebot.types.Message) -> None: """Handle /stats command - show statistics.""" chat_id = message.chat.id db = get_db_session() try: # Check if bot is admin chat = db.query(Chat).filter(Chat.chat_id == chat_id).first() if not chat or not chat.bot_is_admin: bot.reply_to(message, "Мне нужны права администратора для выполнения этой команды.") return # Get total members count (exclude bots) try: total_members_raw = bot.get_chat_member_count(chat_id) # Try to subtract all bots (including this bot) using admin list human_members = total_members_raw try: admins = bot.get_chat_administrators(chat_id) bots_in_admins = sum(1 for m in admins if getattr(m.user, "is_bot", False)) human_members = max(total_members_raw - bots_in_admins, 0) except Exception: human_members = total_members_raw total_members = human_members except Exception: total_members = 0 # Get users who shared birthday users_with_birthday = db.query(User).join(UserChat).filter( UserChat.chat_id == chat_id ).distinct().count() users_without_birthday = max(total_members - users_with_birthday, 0) # Format message if total_members > 0: percentage = (users_with_birthday / total_members) * 100 stats_text = ( f"📊 Статистика чата:\n\n" f"• Всего участников: {total_members}\n" f"• Поделились днем рождения: {users_with_birthday}\n" f"• Не поделились: {users_without_birthday}\n" f"• Процент: {percentage:.1f}%" ) else: stats_text = ( f"📊 Статистика чата:\n\n" f"• Поделились днем рождения: {users_with_birthday}" ) bot.reply_to(message, stats_text) finally: db.close() @bot.message_handler(commands=['week'], chat_types=['group', 'supergroup']) def handle_week(message: telebot.types.Message) -> None: """Handle /week command - show birthdays for next 7 days.""" chat_id = message.chat.id db = get_db_session() try: # Check if bot is admin chat = db.query(Chat).filter(Chat.chat_id == chat_id).first() if not chat or not chat.bot_is_admin: bot.reply_to(message, "Мне нужны права администратора для выполнения этой команды.") return # Get birthdays for next 7 days today = datetime.now().date() birthdays = get_birthdays_in_range(db, chat_id, today, days=7) if not birthdays: bot.reply_to(message, "На ближайшие 7 дней дней рождений не запланировано.") return # Format message message_text = "🎂 Дни рождения на ближайшие 7 дней:\n\n" for date_str, names in sorted(birthdays.items()): names_list = ", ".join(names) message_text += f"• {date_str}: {names_list}\n" bot.reply_to(message, message_text) finally: db.close() @bot.message_handler(commands=['month'], chat_types=['group', 'supergroup']) def handle_month(message: telebot.types.Message) -> None: """Handle /month command - show birthdays for next 31 days.""" chat_id = message.chat.id db = get_db_session() try: # Check if bot is admin chat = db.query(Chat).filter(Chat.chat_id == chat_id).first() if not chat or not chat.bot_is_admin: bot.reply_to(message, "Мне нужны права администратора для выполнения этой команды.") return # Get birthdays for next 31 days today = datetime.now().date() birthdays = get_birthdays_in_range(db, chat_id, today, days=31) if not birthdays: bot.reply_to(message, "На ближайшие 31 день дней рождений не запланировано.") return # Format message message_text = "🎂 Дни рождения на ближайшие 31 день:\n\n" for date_str, names in sorted(birthdays.items()): names_list = ", ".join(names) message_text += f"• {date_str}: {names_list}\n" bot.reply_to(message, message_text) finally: db.close() @bot.message_handler(commands=['help'], chat_types=['group', 'supergroup']) def handle_help(message: telebot.types.Message) -> None: """Handle /help command - show help message.""" help_text = ( "📚 Команды бота:\n\n" "/stats - Показать статистику: сколько человек поделились днем рождения\n" "/week - Показать дни рождения на ближайшие 7 дней\n" "/month - Показать дни рождения на ближайшие 31 день\n" "/help - Показать это сообщение\n\n" "Чтобы поделиться своим днем рождения, напиши боту в личку /start\n\n" "from olly & cursor with <3" ) bot.reply_to(message, help_text) def get_birthdays_in_range(db: Session, chat_id: int, start_date: date, days: int) -> Dict[str, List[str]]: """Get birthdays in the specified date range for users in the chat.""" birthdays = defaultdict(list) # Get all users in this chat users = db.query(User).join(UserChat).filter( UserChat.chat_id == chat_id ).distinct().all() end_date = start_date + timedelta(days=days) for user in users: # Create birthday date for current year try: birthday_this_year = datetime(start_date.year, user.birthday_month, user.birthday_day).date() except ValueError: # Invalid date (e.g., Feb 29 in non-leap year) continue # Check if birthday falls in range if start_date <= birthday_this_year < end_date: date_str = f"{user.birthday_day:02d}.{user.birthday_month:02d}" birthdays[date_str].append(user.first_name) else: # Check next year if we're near year end try: birthday_next_year = datetime(start_date.year + 1, user.birthday_month, user.birthday_day).date() if start_date <= birthday_next_year < end_date: date_str = f"{user.birthday_day:02d}.{user.birthday_month:02d}" birthdays[date_str].append(user.first_name) except ValueError: pass return birthdays