Files
post_bot/handlers/new_post.py
Andrey K. Choi 9793648ee3
Some checks failed
continuous-integration/drone/push Build is failing
security, audit, fom features
2025-09-06 05:03:45 +09:00

122 lines
6.4 KiB
Python

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=[],
)