from telegram import Update, InputMediaPhoto, InputMediaVideo, InputMediaAnimation from telegram.constants import ParseMode, ChatType from telegram.ext import ContextTypes from app.db.session import get_session from app.db.models import Draft, Chat, Delivery from app.bot.keyboards.common import kb_choose_chat from app.bot.messages import READY_SELECT_CHAT, SENT_OK, SEND_ERR, NEED_MEDIA_BEFORE_NEXT, CANCELLED from .drafts import STATE_DRAFT, KEY_DRAFT_ID, STATE_AWAIT_TEXT, STATE_CONFIRM from .add_group import STATE_KEY # чтобы не конфликтовать по user_data ключам async def on_callback(update: Update, ctx: ContextTypes.DEFAULT_TYPE): q = update.callback_query await q.answer() data = q.data # --- Переход с медиа на текст --- if data.startswith("draft_next_text:"): draft_id = int(data.split(":")[1]) with get_session() as s: d = s.get(Draft, draft_id) if not d: await q.edit_message_text("Черновик не найден.") return if len(d.media) == 0: await q.edit_message_text(NEED_MEDIA_BEFORE_NEXT) return ctx.user_data[KEY_DRAFT_ID] = draft_id ctx.user_data[STATE_DRAFT] = STATE_AWAIT_TEXT await q.edit_message_text("Шаг 2/3 — текст.\nОтправьте текст поста.") # --- Подтверждение (Отправить) -> выбор чата --- elif data.startswith("draft_confirm_send:"): draft_id = int(data.split(":")[1]) with get_session() as s: d = s.get(Draft, draft_id) if not d: await q.edit_message_text("Черновик не найден.") return d.status = "ready" s.commit() # Разрешённые чаты владельца черновика chats = s.query(Chat).filter_by(owner_user_id=d.user_id, can_post=True).all() buttons = [(c.title or str(c.chat_id), c.chat_id) for c in chats] kb = kb_choose_chat(draft_id, buttons) if not kb: await q.edit_message_text("Нет чатов с правом публикации. Добавьте/обновите через /add_group.") return ctx.user_data[STATE_DRAFT] = STATE_CONFIRM await q.edit_message_text(READY_SELECT_CHAT, reply_markup=kb) # --- Отмена черновика --- elif data.startswith("draft_cancel:"): draft_id = int(data.split(":")[1]) with get_session() as s: d = s.get(Draft, draft_id) if d: d.status = "cancelled" s.commit() ctx.user_data.pop(KEY_DRAFT_ID, None) ctx.user_data.pop(STATE_DRAFT, None) await q.edit_message_text(CANCELLED) # --- Отправка в выбранный чат --- elif data.startswith("send:"): _, draft_id, chat_id = data.split(":") draft_id = int(draft_id); chat_id = int(chat_id) with get_session() as s: d = s.get(Draft, draft_id) if not d: await q.edit_message_text("Черновик не найден.") return media = list(sorted(d.media, key=lambda m: m.order)) sent_ids = [] try: if media: if len(media) > 1: im = [] for i, m in enumerate(media): cap = d.text if i == 0 else None if m.kind == "photo": im.append(InputMediaPhoto(media=m.file_id, caption=cap, parse_mode=ParseMode.HTML)) elif m.kind == "video": im.append(InputMediaVideo(media=m.file_id, caption=cap, parse_mode=ParseMode.HTML)) elif m.kind == "animation": im.append(InputMediaAnimation(media=m.file_id, caption=cap, parse_mode=ParseMode.HTML)) msgs = await ctx.bot.send_media_group(chat_id=chat_id, media=im) sent_ids = [str(m.message_id) for m in msgs] else: m = media[0] if m.kind == "photo": msg = await ctx.bot.send_photo(chat_id=chat_id, photo=m.file_id, caption=d.text, parse_mode=ParseMode.HTML) elif m.kind == "video": msg = await ctx.bot.send_video(chat_id=chat_id, video=m.file_id, caption=d.text, parse_mode=ParseMode.HTML) else: msg = await ctx.bot.send_animation(chat_id=chat_id, animation=m.file_id, caption=d.text, parse_mode=ParseMode.HTML) sent_ids = [str(msg.message_id)] else: msg = await ctx.bot.send_message(chat_id=chat_id, text=d.text or "(пусто)", parse_mode=ParseMode.HTML) sent_ids = [str(msg.message_id)] deliv = Delivery(draft_id=d.id, chat_id=chat_id, status="sent", message_ids=",".join(sent_ids)) s.add(deliv) d.status = "sent" s.commit() # Сбрасываем пользовательское состояние редактора ctx.user_data.pop(KEY_DRAFT_ID, None) ctx.user_data.pop(STATE_DRAFT, None) await q.edit_message_text(SENT_OK) except Exception as e: deliv = Delivery(draft_id=d.id, chat_id=chat_id, status="failed", error=str(e)) s.add(deliv); s.commit() await q.edit_message_text(SEND_ERR.format(e=e))