745 lines
28 KiB
Python
745 lines
28 KiB
Python
"""Обработчики для работы с постами."""
|
||
from datetime import datetime
|
||
from logging import getLogger
|
||
import re
|
||
from typing import Dict, Any, Optional, cast, Union
|
||
|
||
from telegram import (
|
||
Update,
|
||
Message,
|
||
CallbackQuery,
|
||
ReplyKeyboardMarkup,
|
||
InlineKeyboardMarkup,
|
||
InlineKeyboardButton
|
||
)
|
||
from telegram.ext import (
|
||
ContextTypes,
|
||
ConversationHandler
|
||
)
|
||
from telegram.helpers import escape_markdown
|
||
from telegram.constants import ChatAction, ParseMode
|
||
from telegram.error import BadRequest, Forbidden, TelegramError
|
||
|
||
from ..session import UserSession, SessionStore
|
||
from ..states import BotStates
|
||
from ..keyboards import KbBuilder
|
||
from app.models.post import Post, PostType
|
||
from app.services.template import TemplateService
|
||
from app.services.channels import ChannelService
|
||
from app.services.telegram import PostService
|
||
from ..messages import MessageType
|
||
|
||
logger = getLogger(__name__)
|
||
|
||
def parse_key_value_lines(text: str) -> Dict[str, str]:
|
||
"""Парсит строки в формате 'ключ = значение' в словарь."""
|
||
if not text:
|
||
return {}
|
||
|
||
result = {}
|
||
for line in text.split('\n'):
|
||
if '=' not in line:
|
||
continue
|
||
key, value = map(str.strip, line.split('=', 1))
|
||
if key:
|
||
result[key] = value
|
||
return result
|
||
|
||
logger = getLogger(__name__)
|
||
|
||
logger = getLogger(__name__)
|
||
|
||
async def newpost(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Начало создания нового поста."""
|
||
message = update.effective_message
|
||
user = update.effective_user
|
||
|
||
if not message or not user:
|
||
return ConversationHandler.END
|
||
|
||
try:
|
||
# Создаем новую сессию
|
||
session = SessionStore.get_instance().get(user.id)
|
||
session.clear()
|
||
|
||
# Загружаем список каналов пользователя
|
||
channels = await ChannelService.get_user_channels(user.id)
|
||
if not channels:
|
||
await message.reply_text(
|
||
"У вас нет добавленных каналов. Используйте /add_channel чтобы добавить."
|
||
)
|
||
return ConversationHandler.END
|
||
|
||
kb = KbBuilder.channels(channels)
|
||
await message.reply_text(
|
||
"Выберите канал для публикации:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.CHOOSE_CHANNEL
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in newpost: {e}")
|
||
await message.reply_text("Произошла ошибка при создании поста")
|
||
return ConversationHandler.END
|
||
|
||
async def choose_channel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Обработка выбора канала."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
await message.edit_text("Неверный формат данных")
|
||
return ConversationHandler.END
|
||
|
||
channel_id = int(query.data.replace("channel:", ""))
|
||
|
||
# Проверяем существование канала
|
||
channel = await ChannelService.get_channel(channel_id)
|
||
if not channel:
|
||
await message.edit_text("Канал не найден")
|
||
return ConversationHandler.END
|
||
|
||
session = SessionStore.get_instance().get(query.from_user.id)
|
||
session.channel_id = channel_id
|
||
|
||
kb = KbBuilder.post_types()
|
||
await message.edit_text(
|
||
"Выберите тип поста:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.CHOOSE_TYPE
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in choose_channel: {e}")
|
||
if query.message:
|
||
await query.message.edit_text("Произошла ошибка при выборе канала")
|
||
return ConversationHandler.END
|
||
|
||
async def choose_type(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Обработка выбора типа поста."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
await message.edit_text("Неверный формат данных")
|
||
return ConversationHandler.END
|
||
|
||
post_type = PostType(query.data.replace("type:", ""))
|
||
|
||
session = SessionStore.get_instance().get(query.from_user.id)
|
||
session.type = post_type
|
||
|
||
kb = KbBuilder.parse_modes()
|
||
await message.edit_text(
|
||
"Выберите формат текста:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.CHOOSE_FORMAT
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in choose_type: {e}")
|
||
if query.message:
|
||
await query.message.edit_text("Произошла ошибка при выборе типа поста")
|
||
return ConversationHandler.END
|
||
|
||
async def choose_format(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Обработка выбора формата текста."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
await message.edit_text("Неверный формат данных")
|
||
return ConversationHandler.END
|
||
|
||
parse_mode = query.data.replace("fmt:", "")
|
||
if parse_mode not in [ParseMode.HTML, ParseMode.MARKDOWN_V2]:
|
||
await message.edit_text("Неизвестный формат текста")
|
||
return ConversationHandler.END
|
||
|
||
session = SessionStore.get_instance().get(query.from_user.id)
|
||
session.parse_mode = parse_mode
|
||
|
||
kb = KbBuilder.text_input_options()
|
||
await message.edit_text(
|
||
"Введите текст поста или выберите шаблон:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.ENTER_TEXT
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in choose_format: {e}")
|
||
if query.message:
|
||
await query.message.edit_text("Произошла ошибка при выборе формата")
|
||
return ConversationHandler.END
|
||
|
||
async def enter_text(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Обработка ввода текста поста."""
|
||
message = update.effective_message
|
||
user = update.effective_user
|
||
|
||
if not message or not user:
|
||
return ConversationHandler.END
|
||
|
||
text = message.text
|
||
if not text:
|
||
await message.reply_text("Пожалуйста, введите текст поста")
|
||
return BotStates.ENTER_TEXT
|
||
|
||
try:
|
||
session = SessionStore.get_instance().get(user.id)
|
||
session.text = text
|
||
|
||
if session.type == MessageType.TEXT:
|
||
await message.reply_text(
|
||
"Введите клавиатуру в формате:\n"
|
||
"текст кнопки = ссылка\n\n"
|
||
"Или отправьте 'skip' чтобы пропустить"
|
||
)
|
||
return BotStates.EDIT_KEYBOARD
|
||
|
||
await message.reply_text(
|
||
"Отправьте фото/видео/gif для поста"
|
||
)
|
||
return BotStates.ENTER_MEDIA
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in enter_text: {e}")
|
||
await message.reply_text("Произошла ошибка при сохранении текста")
|
||
return ConversationHandler.END
|
||
|
||
async def choose_template_open(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Открытие выбора шаблона."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
user_id = query.from_user.id
|
||
|
||
templates = await TemplateService.list_user_templates(user_id)
|
||
if not templates:
|
||
await message.edit_text(
|
||
"У вас нет шаблонов. Создайте новый с помощью /newtemplate"
|
||
)
|
||
return BotStates.ENTER_TEXT
|
||
|
||
total = len(templates)
|
||
if total == 0:
|
||
await message.edit_text("Список шаблонов пуст")
|
||
return BotStates.ENTER_TEXT
|
||
|
||
user_data = context.user_data
|
||
if not user_data:
|
||
user_data = {}
|
||
context.user_data = user_data
|
||
|
||
page = user_data.get("tpl_page", 0)
|
||
items = templates[page * KbBuilder.PAGE_SIZE:(page + 1) * KbBuilder.PAGE_SIZE]
|
||
|
||
kb = KbBuilder.templates_list(items, page, total)
|
||
await message.edit_text(
|
||
"Выберите шаблон:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in choose_template_open: {e}")
|
||
if query.message:
|
||
await query.message.edit_text("Произошла ошибка при загрузке шаблонов")
|
||
return ConversationHandler.END
|
||
|
||
async def choose_template_apply(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Применение выбранного шаблона."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
await message.edit_text("Неверный формат данных")
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
template_id = query.data.replace("tpluse:", "")
|
||
|
||
template = await TemplateService.get_template(template_id)
|
||
if not template:
|
||
await message.edit_text("Шаблон не найден")
|
||
return BotStates.ENTER_TEXT
|
||
|
||
session = SessionStore.get_instance().get(query.from_user.id)
|
||
session.template_id = template_id
|
||
session.text = template.content
|
||
|
||
if "{" in template.content and "}" in template.content:
|
||
# Шаблон содержит переменные
|
||
await message.edit_text(
|
||
"Введите значения для переменных в формате:\n"
|
||
"переменная = значение"
|
||
)
|
||
return BotStates.PREVIEW_VARS
|
||
|
||
# Нет переменных, можно сразу показать предпросмотр
|
||
kb = KbBuilder.preview_confirm()
|
||
|
||
post_data = session.to_dict()
|
||
await PostService.preview_post(message, post_data)
|
||
|
||
await message.reply_text(
|
||
"Предпросмотр поста. Выберите действие:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.PREVIEW_CONFIRM
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in choose_template_apply: {e}")
|
||
if query.message:
|
||
await query.message.edit_text(
|
||
"Произошла ошибка при применении шаблона"
|
||
)
|
||
return BotStates.ENTER_TEXT
|
||
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при применении шаблона: {e}")
|
||
await query.message.edit_text(
|
||
f"Ошибка при применении шаблона: {str(e)}"
|
||
)
|
||
return BotStates.ENTER_TEXT
|
||
|
||
async def choose_template_preview(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Предпросмотр шаблона."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
await message.edit_text("Неверный формат данных")
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
template_id = query.data.replace("tplprev:", "")
|
||
template = await TemplateService.get_template(template_id)
|
||
|
||
if not template:
|
||
await message.edit_text("Шаблон не найден")
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
await message.edit_text(
|
||
f"Предпросмотр шаблона:\n\n{template.content}",
|
||
parse_mode=template.parse_mode
|
||
)
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in choose_template_preview: {e}")
|
||
if query.message:
|
||
await query.message.edit_text(
|
||
"Произошла ошибка при предпросмотре шаблона"
|
||
)
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
async def choose_template_navigate(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Навигация по страницам шаблонов."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
# Получаем номер страницы
|
||
page = int(query.data.replace("tplpage:", ""))
|
||
|
||
user_data = context.user_data
|
||
if not user_data:
|
||
user_data = {}
|
||
context.user_data = user_data
|
||
user_data["tpl_page"] = page
|
||
|
||
# Перестраиваем список для новой страницы
|
||
templates = await TemplateService.list_user_templates(query.from_user.id)
|
||
total = len(templates)
|
||
items = templates[page * KbBuilder.PAGE_SIZE:(page + 1) * KbBuilder.PAGE_SIZE]
|
||
|
||
kb = KbBuilder.templates_list(items, page, total)
|
||
await message.edit_reply_markup(reply_markup=kb)
|
||
return BotStates.SELECT_TEMPLATE
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in choose_template_navigate: {e}")
|
||
if query.message:
|
||
await query.message.edit_text("Произошла ошибка при смене страницы")
|
||
return ConversationHandler.END
|
||
|
||
async def choose_template_cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Отмена выбора шаблона."""
|
||
query = update.callback_query
|
||
if not query:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
await query.message.edit_text(
|
||
"Введите текст поста:"
|
||
)
|
||
return BotStates.ENTER_TEXT
|
||
|
||
async def preview_collect_vars(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Сбор значений переменных для шаблона."""
|
||
message = update.message
|
||
if not message or not message.from_user or not message.text:
|
||
return ConversationHandler.END
|
||
|
||
try:
|
||
variables = parse_key_value_lines(message.text)
|
||
session = SessionStore.get_instance().get(message.from_user.id)
|
||
if not session.template_id:
|
||
await message.reply_text("Шаблон не выбран")
|
||
return BotStates.ENTER_TEXT
|
||
|
||
template = await TemplateService.get_template(session.template_id)
|
||
if not template:
|
||
await message.reply_text("Шаблон не найден")
|
||
return BotStates.ENTER_TEXT
|
||
|
||
# Подставляем значения переменных
|
||
text = template.content
|
||
for var, value in variables.items():
|
||
text = text.replace(f"{{{var}}}", value)
|
||
|
||
session.text = text
|
||
post_data = session.to_dict()
|
||
|
||
kb = KbBuilder.preview_confirm()
|
||
await PostService.preview_post(message, post_data)
|
||
|
||
await message.reply_text(
|
||
"Предпросмотр поста. Выберите действие:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.PREVIEW_CONFIRM
|
||
|
||
except ValueError as e:
|
||
await message.reply_text(
|
||
f"Ошибка в формате переменных: {str(e)}\n"
|
||
"Используйте формат:\n"
|
||
"переменная = значение"
|
||
)
|
||
return BotStates.PREVIEW_VARS
|
||
except Exception as e:
|
||
logger.error(f"Error in preview_collect_vars: {e}")
|
||
await message.reply_text(
|
||
"Произошла ошибка при обработке переменных"
|
||
)
|
||
return BotStates.PREVIEW_VARS
|
||
|
||
async def preview_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Подтверждение предпросмотра поста."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
await message.edit_text("Неверный формат данных")
|
||
return BotStates.PREVIEW_CONFIRM
|
||
|
||
action = query.data.replace("pv:", "")
|
||
if action == "edit":
|
||
await message.edit_text(
|
||
"Введите текст поста:"
|
||
)
|
||
return BotStates.ENTER_TEXT
|
||
|
||
session = SessionStore.get_instance().get(query.from_user.id)
|
||
|
||
if not session.type:
|
||
await message.edit_text("Ошибка: не выбран тип поста")
|
||
return ConversationHandler.END
|
||
|
||
if session.type == MessageType.TEXT:
|
||
await message.edit_text(
|
||
"Введите клавиатуру в формате:\n"
|
||
"текст кнопки = ссылка\n\n"
|
||
"Или отправьте 'skip' чтобы пропустить"
|
||
)
|
||
return BotStates.EDIT_KEYBOARD
|
||
|
||
await message.edit_text(
|
||
"Отправьте фото/видео/gif для поста"
|
||
)
|
||
return BotStates.ENTER_MEDIA
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in preview_confirm: {e}")
|
||
if query.message:
|
||
await query.message.edit_text(
|
||
"Произошла ошибка при обработке предпросмотра"
|
||
)
|
||
return ConversationHandler.END
|
||
|
||
async def enter_media(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Обработка медиафайла."""
|
||
message = update.message
|
||
if not message or not message.from_user:
|
||
return ConversationHandler.END
|
||
|
||
try:
|
||
session = SessionStore.get_instance().get(message.from_user.id)
|
||
|
||
if message.photo:
|
||
session.media_file_id = message.photo[-1].file_id
|
||
elif message.video:
|
||
session.media_file_id = message.video.file_id
|
||
elif message.animation:
|
||
session.media_file_id = message.animation.file_id
|
||
elif message.document:
|
||
session.media_file_id = message.document.file_id
|
||
else:
|
||
await message.reply_text(
|
||
"Пожалуйста, отправьте фото, видео или GIF"
|
||
)
|
||
return BotStates.ENTER_MEDIA
|
||
|
||
# Показываем предпросмотр
|
||
kb = KbBuilder.preview_confirm()
|
||
post_data = session.to_dict()
|
||
await PostService.preview_post(message, post_data)
|
||
|
||
await message.reply_text(
|
||
"Предпросмотр поста. Выберите действие:",
|
||
reply_markup=kb
|
||
)
|
||
return BotStates.PREVIEW_CONFIRM
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in enter_media: {e}")
|
||
await message.reply_text(
|
||
"Произошла ошибка при обработке файла"
|
||
)
|
||
return ConversationHandler.END
|
||
session.media_id = message.animation.file_id
|
||
|
||
await message.reply_text(
|
||
"Введите клавиатуру в формате:\n"
|
||
"текст кнопки = ссылка\n\n"
|
||
"Или отправьте 'skip' чтобы пропустить"
|
||
)
|
||
return BotStates.EDIT_KEYBOARD
|
||
|
||
async def edit_keyboard(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Обработка клавиатуры поста."""
|
||
message = update.message
|
||
if not message or not message.from_user or not message.text:
|
||
return ConversationHandler.END
|
||
|
||
try:
|
||
kb_text = message.text.strip()
|
||
session = SessionStore.get_instance().get(message.from_user.id)
|
||
|
||
if kb_text.lower() != "skip":
|
||
keyboard = parse_key_value_lines(kb_text)
|
||
session.keyboard = {"rows": []}
|
||
for text, url in keyboard.items():
|
||
session.keyboard["rows"].append([{"text": text, "url": url}])
|
||
|
||
# Показываем предпросмотр поста
|
||
post_data = session.to_dict()
|
||
await PostService.preview_post(message, post_data)
|
||
|
||
keyboard = InlineKeyboardMarkup([
|
||
[
|
||
InlineKeyboardButton("Отправить", callback_data="send:now"),
|
||
InlineKeyboardButton("Отложить", callback_data="send:schedule")
|
||
]
|
||
])
|
||
|
||
await message.reply_text(
|
||
"Выберите действие:",
|
||
reply_markup=keyboard
|
||
)
|
||
return BotStates.CONFIRM_SEND
|
||
|
||
except ValueError as e:
|
||
await message.reply_text(
|
||
f"Ошибка в формате клавиатуры: {e}\n"
|
||
"Используйте формат:\n"
|
||
"текст кнопки = ссылка"
|
||
)
|
||
return BotStates.EDIT_KEYBOARD
|
||
except Exception as e:
|
||
logger.error(f"Error in edit_keyboard: {e}")
|
||
await message.reply_text(
|
||
"Произошла ошибка при обработке клавиатуры"
|
||
)
|
||
return ConversationHandler.END
|
||
|
||
async def confirm_send(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Подтверждение отправки поста."""
|
||
query = update.callback_query
|
||
if not query or not query.from_user:
|
||
return ConversationHandler.END
|
||
|
||
await query.answer()
|
||
|
||
try:
|
||
message = cast(Message, query.message)
|
||
if not query.data:
|
||
await message.edit_text("Неверный формат данных")
|
||
return BotStates.CONFIRM_SEND
|
||
|
||
action = query.data.replace("send:", "")
|
||
if action == "schedule":
|
||
await message.edit_text(
|
||
"Введите дату и время для отложенной публикации в формате:\n"
|
||
"ДД.ММ.ГГГГ ЧЧ:ММ"
|
||
)
|
||
return BotStates.ENTER_SCHEDULE
|
||
|
||
session = SessionStore.get_instance().get(query.from_user.id)
|
||
|
||
# Отправляем пост сейчас
|
||
post_data = session.to_dict()
|
||
|
||
message = query.message
|
||
if not message:
|
||
return BotStates.PREVIEW_CONFIRM
|
||
|
||
if not session.channel_id:
|
||
await context.bot.send_message(
|
||
chat_id=message.chat.id,
|
||
text="Канал не выбран",
|
||
reply_markup=KbBuilder.go_back()
|
||
)
|
||
return BotStates.PREVIEW_CONFIRM
|
||
|
||
post = await PostService.create_post(context.bot, session.channel_id, post_data)
|
||
if post:
|
||
await context.bot.edit_message_text(
|
||
chat_id=message.chat.id,
|
||
message_id=message.message_id,
|
||
text="Пост успешно отправлен!"
|
||
)
|
||
SessionStore.get_instance().drop(query.from_user.id)
|
||
return ConversationHandler.END
|
||
|
||
await context.bot.send_message(
|
||
chat_id=message.chat.id,
|
||
text="Ошибка при отправке поста. Попробуйте позже.",
|
||
reply_markup=KbBuilder.go_back()
|
||
)
|
||
return BotStates.PREVIEW_CONFIRM
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in confirm_send: {e}")
|
||
message = query.message
|
||
if message:
|
||
await context.bot.edit_message_text(
|
||
chat_id=message.chat.id,
|
||
message_id=message.message_id,
|
||
text="Произошла ошибка при отправке поста"
|
||
)
|
||
return BotStates.PREVIEW_CONFIRM
|
||
return ConversationHandler.END
|
||
|
||
session = get_session_store().get_or_create(query.from_user.id)
|
||
|
||
try:
|
||
# Отправляем пост
|
||
await schedule_post(session, schedule_time=None)
|
||
await query.message.edit_text("Пост успешно отправлен!")
|
||
|
||
# Очищаем сессию
|
||
get_session_store().drop(query.from_user.id)
|
||
return ConversationHandler.END
|
||
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при отправке поста: {e}")
|
||
await query.message.edit_text(
|
||
f"Ошибка при отправке поста: {str(e)}"
|
||
)
|
||
return BotStates.CONFIRM_SEND
|
||
|
||
async def enter_schedule(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||
"""Обработка времени для отложенной публикации."""
|
||
message = update.message
|
||
if not message or not message.from_user or not message.text:
|
||
return ConversationHandler.END
|
||
|
||
try:
|
||
schedule_text = message.text.strip()
|
||
if not schedule_text:
|
||
await message.reply_text(
|
||
"Некорректный формат даты.\n"
|
||
"Используйте формат: ДД.ММ.ГГГГ ЧЧ:ММ"
|
||
)
|
||
return BotStates.ENTER_SCHEDULE
|
||
|
||
try:
|
||
schedule_time = datetime.strptime(schedule_text, "%d.%m.%Y %H:%M")
|
||
if schedule_time <= datetime.now():
|
||
await message.reply_text(
|
||
"Нельзя указать время в прошлом.\n"
|
||
"Введите время в будущем."
|
||
)
|
||
return BotStates.ENTER_SCHEDULE
|
||
|
||
session = SessionStore.get_instance().get(message.from_user.id)
|
||
if not session.channel_id:
|
||
await message.reply_text("Не выбран канал для публикации")
|
||
return ConversationHandler.END
|
||
|
||
# Отправляем отложенный пост
|
||
post_data = session.to_dict()
|
||
post_data["schedule_time"] = schedule_time
|
||
await PostService.create_post(context.bot, session.channel_id, post_data)
|
||
await message.reply_text("Пост запланирован!")
|
||
|
||
# Очищаем сессию
|
||
SessionStore.get_instance().drop(message.from_user.id)
|
||
return ConversationHandler.END
|
||
|
||
except ValueError:
|
||
await message.reply_text(
|
||
"Некорректный формат даты.\n"
|
||
"Используйте формат: ДД.ММ.ГГГГ ЧЧ:ММ"
|
||
)
|
||
return BotStates.ENTER_SCHEDULE
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error in enter_schedule: {e}")
|
||
await message.reply_text(
|
||
"Произошла ошибка при обработке времени публикации"
|
||
)
|
||
return ConversationHandler.END
|