""" Telegram бот для тайного Санты - ИСПРАВЛЕННАЯ ВЕРСИЯ Требует: pip install pyTelegramBotAPI """ import telebot import json import os import random from datetime import datetime # ===== НАСТРОЙКИ ===== # Замените на ваш токен от BotFather BOT_TOKEN = "8585166053:AAEsgD2ioOc-SmV2uCae7xNkrAblxYQyajg" # ID владельца (вас) - просто укажите ТОЛЬКО ВАШ ID OWNER_ID = 1132670685 DATA_FILE = "santa_data.json" DEFAULT_DATA = { "groups": {}, "distributions": {} } # ===== ИНИЦИАЛИЗАЦИЯ ===== bot = telebot.TeleBot(BOT_TOKEN) # ===== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ===== def load_data(): """Загружает данные из JSON""" if os.path.exists(DATA_FILE): with open(DATA_FILE, 'r', encoding='utf-8') as f: return json.load(f) return DEFAULT_DATA.copy() def save_data(data): """Сохраняет данные в JSON""" with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) def is_owner(user_id): """Проверяет, владелец ли пользователь""" return user_id == OWNER_ID def secret_santa_algorithm(participants): """Алгоритм распределения""" names = list(participants.keys()) receivers = names.copy() random.shuffle(receivers) for _ in range(100): valid = True for i, giver in enumerate(names): if giver == receivers[i]: valid = False break if valid: break random.shuffle(receivers) result = {} for giver, receiver in zip(names, receivers): result[giver] = receiver return result def get_keyboard(buttons, row_width=2): """Создает клавиатуру с кнопками""" markup = telebot.types.ReplyKeyboardMarkup(row_width=row_width, resize_keyboard=True) markup.add(*[telebot.types.KeyboardButton(btn) for btn in buttons]) return markup def show_admin_menu(chat_id): """Показывает админ-панель""" markup = get_keyboard([ '➕ Создать группу', '📋 Список групп', '✨ Генерировать распределение', '📢 Отправить результаты', '🔙 Назад' ], row_width=1) bot.send_message( chat_id, "🔑 Панель администратора\n\nВыберите действие:", reply_markup=markup, parse_mode='html' ) def show_participant_menu(chat_id): """Показывает меню участника""" markup = get_keyboard([ '✏️ Присоединиться к группе', '📋 Мои группы', '🔙 Назад' ], row_width=1) bot.send_message( chat_id, "👥 Меню участника\n\nВыберите действие:", reply_markup=markup, parse_mode='html' ) # ===== КОМАНДЫ ===== @bot.message_handler(commands=['start']) def start(message): """Команда /start""" markup = get_keyboard(['👑 Администратор', '👥 Участник'], row_width=1) bot.send_message( message.chat.id, "🎄 Добро пожаловать в бота для тайного Санты!\n\n" "Выберите вашу роль:", reply_markup=markup ) @bot.message_handler(commands=['help']) def help_cmd(message): """Справка""" help_text = """ 🎄 Справка по боту Для администраторов: • Создайте группу • Посмотрите список групп и участников • Генерируйте распределение (когда все добавлены) • Отправьте результаты Для участников: • Присоединитесь к группе (вводите свое имя и название группы) • Получите личное сообщение с получателем подарка Важно: Все должны быть в приватном чате с ботом! """ bot.send_message(message.chat.id, help_text, parse_mode='html') @bot.message_handler(commands=['mystatus']) def my_status(message): """Показывает статус пользователя""" user_id = message.from_user.id username = message.from_user.username or message.from_user.first_name if is_owner(user_id): status = "👑 Вы владелец бота (администратор)" else: status = "👤 Обычный участник" bot.send_message( message.chat.id, f"Ваш статус:\n{status}\n\n" f"ID: {user_id}\n" f"Username: @{username}", parse_mode='html' ) # ===== АДМИНИСТРАТОР ===== @bot.message_handler(func=lambda m: m.text == '👑 Администратор') def admin_role(message): """Выбор роли администратора""" if not is_owner(message.from_user.id): bot.send_message(message.chat.id, "❌ Только владелец бота может быть администратором.") return show_admin_menu(message.chat.id) @bot.message_handler(func=lambda m: m.text == '➕ Создать группу') def create_group(message): """Создание новой группы""" if not is_owner(message.from_user.id): return msg = bot.send_message( message.chat.id, "📝 Введите название группы (например: 'Друзья 2025'):" ) bot.register_next_step_handler(msg, process_group_name) def process_group_name(message): """Обработка названия группы""" group_name = message.text.strip() data = load_data() if group_name in data["groups"]: bot.send_message(message.chat.id, "❌ Группа с таким названием уже существует!") show_admin_menu(message.chat.id) return data["groups"][group_name] = { "created_by": message.from_user.id, "created_at": datetime.now().isoformat(), "participants": {}, "distributed": False } save_data(data) bot.send_message( message.chat.id, f"✅ Группа '{group_name}' создана!\n\n" f"Скажите друзьям:\n" f"Напишите мне в приватный чат, выберите '👥 Участник',\n" f"затем '✏️ Присоединиться к группе',\n" f"введите название группы '{group_name}' и своё имя.", parse_mode='html' ) show_admin_menu(message.chat.id) @bot.message_handler(func=lambda m: m.text == '📋 Список групп') def list_groups(message): """Список всех групп""" if not is_owner(message.from_user.id): return data = load_data() groups = data["groups"] if not groups: bot.send_message(message.chat.id, "📭 Групп еще не создано.") show_admin_menu(message.chat.id) return text = "📋 Список групп:\n\n" for i, (name, info) in enumerate(groups.items(), 1): count = len(info["participants"]) status = "✅ Распределено" if info["distributed"] else "⏳ Ожидание" text += f"{i}. {name}\n Участников: {count}\n Статус: {status}\n" if info["participants"]: text += " Участники: " names = list(info["participants"].keys()) text += ", ".join(names) text += "\n" text += "\n" bot.send_message(message.chat.id, text, parse_mode='html') show_admin_menu(message.chat.id) @bot.message_handler(func=lambda m: m.text == '✨ Генерировать распределение') def generate_distribution(message): """Генерирование распределения Санты""" if not is_owner(message.from_user.id): return data = load_data() groups = list(data["groups"].keys()) if not groups: bot.send_message(message.chat.id, "❌ Групп не найдено!") show_admin_menu(message.chat.id) return markup = get_keyboard(groups, row_width=1) msg = bot.send_message(message.chat.id, "Выберите группу:", reply_markup=markup) bot.register_next_step_handler(msg, lambda m: process_distribution(m, groups)) def process_distribution(message, groups): """Обработка генерирования распределения""" if message.text not in groups: bot.send_message(message.chat.id, "❌ Неверная группа!") show_admin_menu(message.chat.id) return group_name = message.text data = load_data() group = data["groups"][group_name] if len(group["participants"]) < 2: bot.send_message( message.chat.id, f"❌ В группе '{group_name}' должно быть минимум 2 участника!\n" f"Сейчас в группе: {len(group['participants'])} участников.", parse_mode='html' ) show_admin_menu(message.chat.id) return # Генерируем распределение distribution = secret_santa_algorithm(group["participants"]) # Сохраняем результат data["distributions"][group_name] = { "generated_at": datetime.now().isoformat(), "distribution": distribution } data["groups"][group_name]["distributed"] = True save_data(data) bot.send_message( message.chat.id, f"✅ Распределение для группы '{group_name}' сгенерировано!\n\n" f"Участников: {len(distribution)}\n\n" f"Готово к отправке результатов!", parse_mode='html' ) show_admin_menu(message.chat.id) @bot.message_handler(func=lambda m: m.text == '📢 Отправить результаты') def send_results(message): """Отправка результатов участникам""" if not is_owner(message.from_user.id): return data = load_data() distributions = list(data["distributions"].keys()) if not distributions: bot.send_message(message.chat.id, "❌ Нет сгенерированных распределений!") show_admin_menu(message.chat.id) return markup = get_keyboard(distributions, row_width=1) msg = bot.send_message(message.chat.id, "Выберите группу:", reply_markup=markup) bot.register_next_step_handler(msg, lambda m: send_group_results(m, distributions, data)) def send_group_results(message, distributions, data): """Отправка результатов группе""" if message.text not in distributions: bot.send_message(message.chat.id, "❌ Неверная группа!") show_admin_menu(message.chat.id) return group_name = message.text distribution = data["distributions"][group_name]["distribution"] sent_count = 0 failed_count = 0 for giver_name, receiver_name in distribution.items(): # Получаем user_id дарителя из сохранённых данных participant_data = data["groups"][group_name]["participants"][giver_name] user_id = participant_data["user_id"] try: bot.send_message( user_id, f"🎄 Тайный Санта!\n\n" f"Вы дарите подарок: {receiver_name}\n\n" f"Группа: {group_name}\n\n" f"Сохраняйте в секрете! 🤫", parse_mode='html' ) sent_count += 1 except Exception as e: failed_count += 1 print(f"Ошибка отправки {user_id} ({giver_name}): {e}") result_msg = ( f"✅ Результаты отправлены!\n\n" f"Успешно отправлено: {sent_count}\n" ) if failed_count > 0: result_msg += f"Ошибок: {failed_count}\n" bot.send_message(message.chat.id, result_msg, parse_mode='html') show_admin_menu(message.chat.id) # ===== УЧАСТНИК ===== @bot.message_handler(func=lambda m: m.text == '👥 Участник') def participant_role(message): """Выбор роли участника""" show_participant_menu(message.chat.id) @bot.message_handler(func=lambda m: m.text == '✏️ Присоединиться к группе') def join_group(message): """Присоединение к группе""" data = load_data() groups = list(data["groups"].keys()) if not groups: bot.send_message(message.chat.id, "❌ Групп еще не создано. Попросите администратора создать группу.") show_participant_menu(message.chat.id) return markup = get_keyboard(groups, row_width=1) msg = bot.send_message( message.chat.id, "Выберите группу, к которой хотите присоединиться:", reply_markup=markup ) bot.register_next_step_handler(msg, lambda m: select_group_to_join(m, groups, message.from_user.id)) def select_group_to_join(message, groups, user_id): """Выбор группы для присоединения""" if message.text not in groups: bot.send_message(message.chat.id, "❌ Неверная группа!") show_participant_menu(message.chat.id) return selected_group = message.text msg = bot.send_message( message.chat.id, f"📝 Введите своё имя для группы '{selected_group}':", parse_mode='html' ) bot.register_next_step_handler(msg, lambda m: add_self_to_group(m, selected_group, user_id)) def add_self_to_group(message, group_name, user_id): """Добавление себя в группу""" participant_name = message.text.strip() data = load_data() if participant_name in data["groups"][group_name]["participants"]: bot.send_message( message.chat.id, f"❌ В группе '{group_name}' уже есть участник с именем '{participant_name}'.\n" f"Введите другое имя или прозвище.", parse_mode='html' ) show_participant_menu(message.chat.id) return # ⭐ ГЛАВНОЕ: сохраняем user_id участника! data["groups"][group_name]["participants"][participant_name] = { "user_id": user_id, "added_at": datetime.now().isoformat() } save_data(data) bot.send_message( message.chat.id, f"✅ Отлично! Вы добавлены в группу '{group_name}' под именем '{participant_name}'.\n\n" f"Администратор пришлёт вам результаты, когда сгенерирует распределение.", parse_mode='html' ) show_participant_menu(message.chat.id) @bot.message_handler(func=lambda m: m.text == '📋 Мои группы') def my_groups(message): """Показывает группы пользователя""" user_id = message.from_user.id data = load_data() user_groups = [] for group_name, group_info in data["groups"].items(): for participant_name, participant_info in group_info["participants"].items(): if participant_info["user_id"] == user_id: user_groups.append((group_name, participant_name, group_info["distributed"])) if not user_groups: bot.send_message(message.chat.id, "📭 Вы еще не присоединились ни к одной группе.") show_participant_menu(message.chat.id) return text = "📋 Ваши группы:\n\n" for group_name, participant_name, distributed in user_groups: status = "✅ Распределено" if distributed else "⏳ Ожидание" text += f"• {group_name}\n Ваше имя: {participant_name}\n Статус: {status}\n\n" bot.send_message(message.chat.id, text, parse_mode='html') show_participant_menu(message.chat.id) # ===== НАВИГАЦИЯ ===== @bot.message_handler(func=lambda m: m.text == '🔙 Назад') def back(message): """Возврат в главное меню""" markup = get_keyboard(['👑 Администратор', '👥 Участник'], row_width=1) bot.send_message( message.chat.id, "Выберите вашу роль:", reply_markup=markup ) @bot.message_handler(commands=['about']) def about(message): """Информация о боте""" bot.send_message( message.chat.id, "🎄 Telegram бот для тайного Санты v1.2\n\n" "✨ Как работает:\n" "1. Администратор создаёт группу\n" "2. Участники сами присоединяются к группе\n" "3. Администратор генерирует распределение\n" "4. Каждый получает личное сообщение с получателем\n\n" "/help - справка", parse_mode='html' ) @bot.message_handler(func=lambda m: True) def unknown_message(message): """Обработка неизвестных сообщений""" bot.send_message( message.chat.id, "❓ Команда не распознана.\n\n" "Используйте /start для начала работы или /help для справки." ) # ===== ЗАПУСК БОТА ===== if __name__ == '__main__': print("🤖 Бот запущен! (Нажмите Ctrl+C для остановки)") try: bot.infinity_polling() except KeyboardInterrupt: print("⛔ Бот остановлен.")