import sys import asyncio if sys.platform.startswith('win'): asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) import logging import os from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackQueryHandler, ConversationHandler, ContextTypes from dotenv import load_dotenv from db import AsyncSessionLocal, init_db from models import Admin, Channel, Group, Button from asyncio import run as sync_to_async from handlers.admin_panel import admin_panel_conv load_dotenv() TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN') logging.basicConfig(level=logging.INFO) logging.getLogger("httpx").setLevel(logging.WARNING) logger = logging.getLogger(__name__) import asyncio from telegram.ext import CommandHandler from sqlalchemy import select from datetime import datetime from db import AsyncSessionLocal from models import ChannelAccess from handlers.permissions import get_or_create_admin, token_hash async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): args = (context.args or []) if args and args[0].startswith("sch_"): # формат: sch__ try: _, sid, token = args[0].split("_", 2) invite_id = int(sid) except Exception: await update.message.reply_text("Неверная ссылка приглашения.") return async with AsyncSessionLocal() as session: me = await get_or_create_admin(session, update.effective_user.id) res = await session.execute(select(ChannelAccess).where(ChannelAccess.id == invite_id)) acc = res.scalar_one_or_none() if not acc or acc.status != "pending": await update.message.reply_text("Приглашение не найдено или уже активировано/отозвано.") return if acc.expires_at and acc.expires_at < datetime.utcnow(): await update.message.reply_text("Срок действия приглашения истёк.") return if token_hash(token) != acc.token_hash: await update.message.reply_text("Неверный токен приглашения.") return acc.invited_admin_id = me.id acc.accepted_at = datetime.utcnow() acc.status = "active" await session.commit() await update.message.reply_text("Доступ к каналу успешно активирован. Можно постить через /new_post.") return async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE): help_text = ( "Справка по командам бота:\n\n" "/start — регистрация пользователя как администратора.\n" "/help — показать это подробное описание команд.\n\n" "/add_channel <название> <ссылка> — добавить канал для публикаций. Пример: /add_channel MyChannel @my_channel\n" "/add_group <название> <ссылка> — добавить группу для публикаций. Пример: /add_group MyGroup @my_group\n" "/add_button — добавить кнопку к выбранному каналу или группе. Запустит диалог выбора и добавления.\n" "/edit_button <название> <новое_название> <новая_ссылка> — изменить кнопку. Пример: /edit_button old new https://site.ru\n" "/del_button <название> — удалить кнопку по названию.\n" "/new_post — создать новый пост (картинка + текст + выбор канала/группы + кнопки).\n" "/group_buttons — показать и настроить кнопки для группы.\n" "/channel_buttons — показать и настроить кнопки для канала.\n\n" "Примеры использования:\n" "- /add_channel Новости @news_channel\n" "- /add_group Чат @chat_group\n" "- /edit_button Подписка Subscribe https://subscribe.ru\n" "- /del_button Subscribe\n\n" "Порядок работы:\n" "1. Добавьте канал или группу.\n" "2. Добавьте кнопки для них.\n" "3. Создайте пост через /new_post и выберите, куда отправить.\n" "4. Управляйте кнопками через /group_buttons и /channel_buttons.\n\n" "Если возникли вопросы — используйте /help или обратитесь к администратору." ) if update.message: await update.message.reply_text(help_text, parse_mode='HTML') # Импорт обработчиков from handlers.add_channel import add_channel_conv from handlers.add_group import add_group_conv from handlers.add_button import add_button_conv from handlers.new_post import new_post_conv from handlers.group_buttons import group_buttons_conv from handlers.channel_buttons import channel_buttons_conv from handlers.edit_button import edit_button from handlers.del_button import del_button from handlers.share_channel import share_channel_conv def main(): if not TELEGRAM_TOKEN: print("Ошибка: TELEGRAM_TOKEN не найден в переменных окружения.") return # sync_to_async(init_db()) application = Application.builder().token(TELEGRAM_TOKEN).build() application.add_handler(CommandHandler('start', start)) application.add_handler(CommandHandler('help', help_command)) application.add_handler(add_channel_conv) application.add_handler(add_group_conv) application.add_handler(add_button_conv) application.add_handler(new_post_conv) application.add_handler(group_buttons_conv) application.add_handler(channel_buttons_conv) application.add_handler(CommandHandler('edit_button', edit_button)) application.add_handler(CommandHandler('del_button', del_button)) application.add_handler(admin_panel_conv) application.add_handler(share_channel_conv) import sys import asyncio if sys.platform.startswith('win'): asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) try: loop = asyncio.get_event_loop() except RuntimeError: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) application.run_polling() if __name__ == "__main__": main()