from datetime import datetime from telegram import Update, InputMediaPhoto, InputMediaVideo, InputMediaAnimation from telegram.constants import ChatType, ParseMode from telegram.ext import ContextTypes from app.db.session import get_session from app.db.models import User, Draft from app.bot.messages import ASK_MEDIA, ASK_TEXT, CONFIRM, NEED_START_NEW from app.bot.keyboards.common import kb_next_text, kb_confirm from .add_group import add_group_capture, STATE_KEY STATE_DRAFT = "draft_state" KEY_DRAFT_ID = "draft_id" STATE_AWAIT_MEDIA = "await_media" STATE_AWAIT_TEXT = "await_text" STATE_CONFIRM = "confirm" def _start_new_draft(tg_id: int) -> Draft: with get_session() as s: u = s.query(User).filter_by(tg_id=tg_id).first() if not u: u = User(tg_id=tg_id, name=""); s.add(u); s.commit(); s.refresh(u) s.query(Draft).filter(Draft.user_id == u.id, Draft.status == "editing").update({"status": "cancelled"}) d = Draft(user_id=u.id, status="editing") s.add(d); s.commit(); s.refresh(d) return d async def new_cmd(update: Update, ctx: ContextTypes.DEFAULT_TYPE): d = _start_new_draft(update.effective_user.id) ctx.user_data[KEY_DRAFT_ID] = d.id ctx.user_data[STATE_DRAFT] = STATE_AWAIT_MEDIA # Кнопку «Дальше — текст» теперь показываем после добавления медиа, # поэтому здесь — только инструкция await update.effective_message.reply_text(ASK_MEDIA) async def on_text(update: Update, ctx: ContextTypes.DEFAULT_TYPE): # Если ждём chat_id для /add_group — передаём управление if ctx.user_data.get("await_dict_file"): return if ctx.user_data.get(STATE_KEY): return await add_group_capture(update, ctx) if update.effective_chat.type != ChatType.PRIVATE: return draft_id = ctx.user_data.get(KEY_DRAFT_ID) state = ctx.user_data.get(STATE_DRAFT) if not draft_id or not state: await update.effective_message.reply_text(NEED_START_NEW) return if state == STATE_AWAIT_MEDIA: await update.effective_message.reply_text("Сначала добавьте медиа и нажмите «Дальше — текст».") return if state == STATE_CONFIRM: await update.effective_message.reply_text("Пост уже готов — нажмите «Отправить» или «Отменить».") return if state == STATE_AWAIT_TEXT: # Сохраняем текст with get_session() as s: d = s.get(Draft, draft_id) d.text = update.effective_message.text_html_urled d.updated_at = datetime.utcnow() s.commit() media = sorted(d.media, key=lambda m: m.order) # Предпросмотр 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)) else: im.append(InputMediaAnimation(media=m.file_id, caption=cap, parse_mode=ParseMode.HTML)) await update.effective_chat.send_media_group(media=im) else: m = media[0] if m.kind == "photo": await update.effective_chat.send_photo(photo=m.file_id, caption=d.text, parse_mode=ParseMode.HTML) elif m.kind == "video": await update.effective_chat.send_video(video=m.file_id, caption=d.text, parse_mode=ParseMode.HTML) else: await update.effective_chat.send_animation(animation=m.file_id, caption=d.text, parse_mode=ParseMode.HTML) else: await update.effective_chat.send_message(text=d.text or "(пусто)", parse_mode=ParseMode.HTML) # Переходим к подтверждению и показываем кнопки ctx.user_data[STATE_DRAFT] = STATE_CONFIRM await update.effective_message.reply_text(CONFIRM, reply_markup=kb_confirm(draft_id))