bot rafactor and bugfix

This commit is contained in:
2025-08-19 04:45:16 +09:00
parent 43dda889f8
commit a8d860ed87
31 changed files with 4396 additions and 613 deletions

View File

View File

@@ -0,0 +1,43 @@
"""Базовые обработчики."""
from telegram import Update
from telegram.ext import ContextTypes, ConversationHandler
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Обработчик команды /start."""
if not update.message:
return ConversationHandler.END
await update.message.reply_text(
"Привет! Я бот для управления постами.\n"
"Для создания шаблона используйте /newtemplate\n"
"Для создания поста используйте /newpost\n"
"Для просмотра шаблонов /templates\n"
"Для помощи /help"
)
return ConversationHandler.END
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Обработчик команды /help."""
if not update.message:
return ConversationHandler.END
await update.message.reply_text(
"Доступные команды:\n"
"/start - начать работу с ботом\n"
"/newtemplate - создать новый шаблон\n"
"/templates - просмотреть существующие шаблоны\n"
"/newpost - создать новый пост\n"
"/cancel - отменить текущую операцию"
)
return ConversationHandler.END
async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Отмена текущей операции."""
if not update.message:
return ConversationHandler.END
await update.message.reply_text(
"Операция отменена.",
reply_markup=None
)
return ConversationHandler.END

View File

@@ -0,0 +1,744 @@
"""Обработчики для работы с постами."""
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

View File

@@ -0,0 +1,146 @@
"""Обработчики для работы с шаблонами."""
from typing import Optional, Dict, Any
from telegram import Update, Message
from telegram.ext import ContextTypes, ConversationHandler
from app.bots.editor.states import BotStates
from app.bots.editor.session import get_session_store
from ..keyboards import template_type_keyboard, get_templates_keyboard
from ..utils.parsers import parse_key_value_lines
from ..utils.validation import validate_template_name
async def start_template_creation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
"""Начало создания шаблона."""
if not update.message:
return BotStates.CONVERSATION_END
message = update.message
await message.reply_text(
"Выберите тип шаблона:",
reply_markup=template_type_keyboard()
)
return BotStates.TPL_TYPE
async def handle_template_type(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
"""Обработка выбора типа шаблона."""
if not update.callback_query:
return BotStates.CONVERSATION_END
query = update.callback_query
await query.answer()
tpl_type = query.data
user_id = query.from_user.id
session_store = get_session_store()
session = session_store.get_or_create(user_id)
session.type = tpl_type
await query.message.edit_text("Введите название шаблона:")
return BotStates.TPL_NAME
async def handle_template_name(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
"""Обработка ввода имени шаблона."""
if not update.message:
return BotStates.CONVERSATION_END
message = update.message
user_id = message.from_user.id
name = message.text.strip()
if not validate_template_name(name):
await message.reply_text(
"Некорректное имя шаблона. Используйте только буквы, цифры и знаки - _"
)
return BotStates.TPL_NAME
session = get_session_store().get_or_create(user_id)
session.template_name = name
await message.reply_text("Введите текст шаблона:")
return BotStates.TPL_TEXT
async def handle_template_text(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
"""Обработка текста шаблона."""
if not update.message:
return BotStates.CONVERSATION_END
message = update.message
user_id = message.from_user.id
text = message.text.strip()
session = get_session_store().get_or_create(user_id)
session.text = text
await message.reply_text(
"Введите клавиатуру в формате:\n"
"текст кнопки = ссылка\n\n"
"Или отправьте 'skip' чтобы пропустить"
)
return BotStates.TPL_NEW_KB
async def handle_template_keyboard(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
"""Обработка клавиатуры шаблона."""
if not update.message:
return BotStates.CONVERSATION_END
message = update.message
user_id = message.from_user.id
kb_text = message.text.strip()
session = get_session_store().get_or_create(user_id)
if kb_text != "skip":
try:
keyboard = parse_key_value_lines(kb_text)
session.keyboard = keyboard
except ValueError as e:
await message.reply_text(f"Ошибка разбора клавиатуры: {e}")
return BotStates.TPL_NEW_KB
try:
template_data = {
"owner_id": user_id,
"name": session.template_name,
"title": session.template_name,
"content": session.text,
"type": session.type,
"parse_mode": session.parse_mode or "HTML",
"keyboard_tpl": session.keyboard
}
await create_template(template_data)
await message.reply_text("Шаблон успешно создан")
# Очищаем сессию
get_session_store().drop(user_id)
return BotStates.CONVERSATION_END
except ValueError as e:
await message.reply_text(f"Ошибка создания шаблона: {e}")
return BotStates.TPL_NEW_KB
except Exception as e:
logger.error(f"Неожиданная ошибка при создании шаблона: {e}")
await message.reply_text("Произошла непредвиденная ошибка при создании шаблона")
return BotStates.TPL_NEW_KB
async def list_templates(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
"""Список шаблонов."""
if not update.message:
return BotStates.CONVERSATION_END
message = update.message
user_id = message.from_user.id
templates = await get_user_templates(user_id)
if not templates:
await message.reply_text("У вас пока нет шаблонов")
return BotStates.CONVERSATION_END
page = context.user_data.get("tpl_page", 0)
keyboard = get_templates_keyboard(templates, page)
await message.reply_text(
"Выберите шаблон:",
reply_markup=keyboard
)
return BotStates.TPL_SELECT