from telegram import Update, InputMediaPhoto, InlineKeyboardMarkup, InlineKeyboardButton from telegram.ext import ContextTypes, ConversationHandler, MessageHandler, CommandHandler, filters, CallbackQueryHandler, ContextTypes from db import AsyncSessionLocal from models import Channel, Group, Button, Admin SELECT_MEDIA, SELECT_TEXT, SELECT_TARGET = range(3) async def new_post_start(update: Update, context: ContextTypes.DEFAULT_TYPE): if update.message: await update.message.reply_text('Отправьте картинку для поста или /skip:') return SELECT_MEDIA return ConversationHandler.END async def select_media(update: Update, context: ContextTypes.DEFAULT_TYPE): if update.message and hasattr(update.message, 'photo') and update.message.photo: if context.user_data is None: context.user_data = {} context.user_data['photo'] = update.message.photo[-1].file_id if update.message: await update.message.reply_text('Введите текст поста или пересланное сообщение:') return SELECT_TEXT return ConversationHandler.END async def select_text(update: Update, context: ContextTypes.DEFAULT_TYPE): if update.message: if context.user_data is None: context.user_data = {} context.user_data['text'] = getattr(update.message, 'text', None) or getattr(update.message, 'caption', None) from sqlalchemy import select session = AsyncSessionLocal() user_id = update.effective_user.id if update.effective_user else None try: # Ограничиваем каналы и группы только теми, где пользователь — админ channels_result = await session.execute( select(Channel).join(Button, isouter=True).join(Group, isouter=True) .join(Admin, Channel.id == Admin.channel_id) .where(Admin.tg_id == user_id) ) channels = channels_result.scalars().all() groups_result = await session.execute( select(Group).join(Button, isouter=True) .join(Admin, Group.id == Admin.channel_id) .where(Admin.tg_id == user_id) ) groups = groups_result.scalars().all() keyboard = [] for c in channels: keyboard.append([InlineKeyboardButton(f'Канал: {getattr(c, "name", str(c.name))}', callback_data=f'channel_{getattr(c, "id", str(c.id))}')]) for g in groups: keyboard.append([InlineKeyboardButton(f'Группа: {getattr(g, "name", str(g.name))}', callback_data=f'group_{getattr(g, "id", str(g.id))}')]) reply_markup = InlineKeyboardMarkup(keyboard) await update.message.reply_text('Выберите, куда отправить пост:', reply_markup=reply_markup) # Сохраняем id исходного сообщения для пересылки context.user_data['forward_message_id'] = update.message.message_id context.user_data['forward_chat_id'] = update.message.chat_id return SELECT_TARGET finally: await session.close() return ConversationHandler.END async def select_target(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query if not query: return ConversationHandler.END await query.answer() data = query.data session = AsyncSessionLocal() try: chat_id = None markup = None if data and data.startswith('channel_'): from sqlalchemy import select channel_id = int(data.split('_')[1]) channel_result = await session.execute(select(Channel).where(Channel.id == channel_id)) channel = channel_result.scalar_one_or_none() buttons_result = await session.execute(select(Button).where(Button.channel_id == channel_id)) buttons = buttons_result.scalars().all() markup = InlineKeyboardMarkup([[InlineKeyboardButton(str(b.name), url=str(b.url))] for b in buttons]) if buttons else None chat_id = getattr(channel, 'link', None) elif data and data.startswith('group_'): from sqlalchemy import select group_id = int(data.split('_')[1]) group_result = await session.execute(select(Group).where(Group.id == group_id)) group = group_result.scalar_one_or_none() buttons_result = await session.execute(select(Button).where(Button.group_id == group_id)) buttons = buttons_result.scalars().all() markup = InlineKeyboardMarkup([[InlineKeyboardButton(str(b.name), url=str(b.url))] for b in buttons]) if buttons else None chat_id = getattr(group, 'link', None) if chat_id: chat_id = chat_id.strip() if not (chat_id.startswith('@') or chat_id.startswith('-')): await query.edit_message_text('Ошибка: ссылка должна быть username (@channel) или числовой ID (-100...)') return ConversationHandler.END try: # Пересылка исходного сообщения await context.bot.forward_message( chat_id=chat_id, from_chat_id=context.user_data.get('forward_chat_id'), message_id=context.user_data.get('forward_message_id') ) from db import log_action user_id = update.effective_user.id if update.effective_user else None log_action(user_id, "forward_post", f"chat_id={chat_id}, from_chat_id={context.user_data.get('forward_chat_id')}, message_id={context.user_data.get('forward_message_id')}") await query.edit_message_text('Пост переслан!') except Exception as e: await query.edit_message_text(f'Ошибка пересылки поста: {e}') finally: await session.close() return ConversationHandler.END new_post_conv = ConversationHandler( entry_points=[CommandHandler('new_post', new_post_start)], states={ SELECT_MEDIA: [MessageHandler(filters.PHOTO | filters.Document.IMAGE | filters.COMMAND, select_media)], SELECT_TEXT: [MessageHandler(filters.TEXT | filters.FORWARDED, select_text)], SELECT_TARGET: [CallbackQueryHandler(select_target)], }, fallbacks=[], )