bot works as echo (adding templates s functional)
tpl_list dont
This commit is contained in:
@@ -1,13 +1,27 @@
|
|||||||
"""Обработчики для работы с шаблонами."""
|
"""Обработчики для работы с шаблонами."""
|
||||||
from typing import Optional, Dict, Any
|
import logging
|
||||||
from telegram import Update, Message
|
import logging
|
||||||
|
import re
|
||||||
|
import logging
|
||||||
|
from typing import Optional, Dict, Any, cast
|
||||||
|
from telegram import Update, Message, CallbackQuery
|
||||||
from telegram.ext import ContextTypes, ConversationHandler
|
from telegram.ext import ContextTypes, ConversationHandler
|
||||||
|
from telegram.error import BadRequest
|
||||||
|
|
||||||
from app.bots.editor.states import BotStates
|
from app.bots.editor.states import BotStates
|
||||||
from app.bots.editor.session import get_session_store
|
from app.bots.editor.session import get_session_store
|
||||||
from ..keyboards import template_type_keyboard, get_templates_keyboard
|
from ..keyboards import (
|
||||||
|
template_type_keyboard,
|
||||||
|
get_templates_keyboard,
|
||||||
|
get_preview_keyboard
|
||||||
|
)
|
||||||
from ..utils.parsers import parse_key_value_lines
|
from ..utils.parsers import parse_key_value_lines
|
||||||
from ..utils.validation import validate_template_name
|
from ..utils.validation import validate_template_name
|
||||||
|
from app.services.users import get_or_create_user
|
||||||
|
from app.services.template import list_templates as get_user_templates_list
|
||||||
|
from app.services.template import create_template
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
async def start_template_creation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
|
async def start_template_creation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
|
||||||
"""Начало создания шаблона."""
|
"""Начало создания шаблона."""
|
||||||
@@ -123,24 +137,174 @@ async def handle_template_keyboard(update: Update, context: ContextTypes.DEFAULT
|
|||||||
await message.reply_text("Произошла непредвиденная ошибка при создании шаблона")
|
await message.reply_text("Произошла непредвиденная ошибка при создании шаблона")
|
||||||
return BotStates.TPL_NEW_KB
|
return BotStates.TPL_NEW_KB
|
||||||
|
|
||||||
|
def extract_template_vars(content: str) -> list[str]:
|
||||||
|
"""Извлекает переменные из текста шаблона."""
|
||||||
|
import re
|
||||||
|
pattern = r'\{([^}]+)\}'
|
||||||
|
return list(set(re.findall(pattern, content)))
|
||||||
|
|
||||||
async def list_templates(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
|
async def list_templates(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
|
||||||
"""Список шаблонов."""
|
"""Список шаблонов."""
|
||||||
if not update.message:
|
if not update.message or not update.message.from_user:
|
||||||
return BotStates.CONVERSATION_END
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
message = update.message
|
try:
|
||||||
user_id = message.from_user.id
|
message = update.message
|
||||||
|
tg_user = message.from_user
|
||||||
templates = await get_user_templates(user_id)
|
|
||||||
if not templates:
|
# Получаем или создаем пользователя
|
||||||
await message.reply_text("У вас пока нет шаблонов")
|
user = await get_or_create_user(tg_user_id=tg_user.id, username=tg_user.username)
|
||||||
|
|
||||||
|
# Получаем шаблоны пользователя
|
||||||
|
templates = await get_user_templates_list(owner_id=user.id)
|
||||||
|
|
||||||
|
if not templates:
|
||||||
|
await message.reply_text("Нет доступных шаблонов")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
# Сохраняем шаблоны в контексте
|
||||||
|
context.user_data['templates'] = {str(t.id): t for t in templates}
|
||||||
|
|
||||||
|
# Создаем клавиатуру с шаблонами
|
||||||
|
keyboard = get_templates_keyboard(templates)
|
||||||
|
|
||||||
|
await message.reply_text(
|
||||||
|
"Выберите шаблон для использования:",
|
||||||
|
reply_markup=keyboard
|
||||||
|
)
|
||||||
|
return BotStates.SELECT_TEMPLATE
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка загрузки шаблонов: {e}", exc_info=True)
|
||||||
|
if update.message:
|
||||||
|
await update.message.reply_text(f"Ошибка загрузки шаблонов: {e}")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
async def handle_template_selection(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
|
||||||
|
"""Обработка выбора шаблона."""
|
||||||
|
query = update.callback_query
|
||||||
|
if not query:
|
||||||
return BotStates.CONVERSATION_END
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
page = context.user_data.get("tpl_page", 0)
|
await query.answer()
|
||||||
keyboard = get_templates_keyboard(templates, page)
|
|
||||||
|
|
||||||
await message.reply_text(
|
try:
|
||||||
"Выберите шаблон:",
|
template_id = query.data.split(":")[1]
|
||||||
reply_markup=keyboard
|
template = context.user_data['templates'].get(template_id)
|
||||||
)
|
|
||||||
return BotStates.TPL_SELECT
|
if not template:
|
||||||
|
await query.message.edit_text("Шаблон не найден")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
# Сохраняем выбранный шаблон
|
||||||
|
context.user_data['current_template'] = template
|
||||||
|
|
||||||
|
# Извлекаем переменные из шаблона
|
||||||
|
vars_needed = extract_template_vars(template.content)
|
||||||
|
|
||||||
|
if not vars_needed:
|
||||||
|
# Если переменных нет, сразу показываем предпросмотр
|
||||||
|
rendered_text = template.content
|
||||||
|
keyboard = get_preview_keyboard()
|
||||||
|
await query.message.edit_text(
|
||||||
|
f"Предпросмотр:\n\n{rendered_text}",
|
||||||
|
reply_markup=keyboard,
|
||||||
|
parse_mode=template.parse_mode
|
||||||
|
)
|
||||||
|
return BotStates.PREVIEW_CONFIRM
|
||||||
|
|
||||||
|
# Сохраняем список необходимых переменных
|
||||||
|
context.user_data['vars_needed'] = vars_needed
|
||||||
|
context.user_data['template_vars'] = {}
|
||||||
|
|
||||||
|
# Запрашиваем первую переменную
|
||||||
|
await query.message.edit_text(
|
||||||
|
f"Введите значение для переменной {vars_needed[0]}:"
|
||||||
|
)
|
||||||
|
return BotStates.TEMPLATE_VARS
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при выборе шаблона: {e}", exc_info=True)
|
||||||
|
await query.message.edit_text(f"Произошла ошибка: {e}")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
async def handle_template_vars(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
|
||||||
|
"""Обработка ввода значений переменных шаблона."""
|
||||||
|
if not update.message or not update.message.text:
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
try:
|
||||||
|
vars_needed = context.user_data.get('vars_needed', [])
|
||||||
|
template_vars = context.user_data.get('template_vars', {})
|
||||||
|
template = context.user_data.get('current_template')
|
||||||
|
|
||||||
|
if not vars_needed or not template:
|
||||||
|
await update.message.reply_text("Ошибка: данные шаблона потеряны")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
# Сохраняем введенное значение
|
||||||
|
current_var = vars_needed[len(template_vars)]
|
||||||
|
template_vars[current_var] = update.message.text
|
||||||
|
context.user_data['template_vars'] = template_vars
|
||||||
|
|
||||||
|
# Проверяем, все ли переменные заполнены
|
||||||
|
if len(template_vars) == len(vars_needed):
|
||||||
|
# Формируем предпросмотр
|
||||||
|
rendered_text = template.content
|
||||||
|
for var, value in template_vars.items():
|
||||||
|
rendered_text = rendered_text.replace(f"{{{var}}}", value)
|
||||||
|
|
||||||
|
keyboard = get_preview_keyboard()
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"Предпросмотр:\n\n{rendered_text}",
|
||||||
|
reply_markup=keyboard,
|
||||||
|
parse_mode=template.parse_mode
|
||||||
|
)
|
||||||
|
return BotStates.PREVIEW_CONFIRM
|
||||||
|
|
||||||
|
# Запрашиваем следующую переменную
|
||||||
|
next_var = vars_needed[len(template_vars)]
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"Введите значение для переменной {next_var}:"
|
||||||
|
)
|
||||||
|
return BotStates.TEMPLATE_VARS
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при обработке переменных: {e}", exc_info=True)
|
||||||
|
await update.message.reply_text(f"Произошла ошибка: {e}")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
async def handle_preview_confirmation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> BotStates:
|
||||||
|
"""Обработка подтверждения предпросмотра."""
|
||||||
|
query = update.callback_query
|
||||||
|
if not query:
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
await query.answer()
|
||||||
|
|
||||||
|
try:
|
||||||
|
action = query.data.split(":")[1]
|
||||||
|
|
||||||
|
if action == "cancel":
|
||||||
|
await query.message.edit_text("Отправка отменена")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
if action == "send":
|
||||||
|
template = context.user_data.get('current_template')
|
||||||
|
template_vars = context.user_data.get('template_vars', {})
|
||||||
|
|
||||||
|
if not template:
|
||||||
|
await query.message.edit_text("Ошибка: данные шаблона потеряны")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
# TODO: Добавить логику отправки в канал
|
||||||
|
await query.message.edit_text(
|
||||||
|
"Пост успешно отправлен\n\n" +
|
||||||
|
"(Здесь будет реальная отправка в канал)"
|
||||||
|
)
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при подтверждении: {e}", exc_info=True)
|
||||||
|
await query.message.edit_text(f"Произошла ошибка: {e}")
|
||||||
|
return BotStates.CONVERSATION_END
|
||||||
|
|||||||
@@ -10,7 +10,27 @@ def template_type_keyboard() -> InlineKeyboardMarkup:
|
|||||||
|
|
||||||
def get_templates_keyboard(templates: List[Any], page: int = 0) -> InlineKeyboardMarkup:
|
def get_templates_keyboard(templates: List[Any], page: int = 0) -> InlineKeyboardMarkup:
|
||||||
"""Возвращает клавиатуру со списком шаблонов."""
|
"""Возвращает клавиатуру со списком шаблонов."""
|
||||||
return KbBuilder.get_templates_keyboard(templates, page)
|
keyboard = []
|
||||||
|
|
||||||
|
for template in templates:
|
||||||
|
keyboard.append([
|
||||||
|
InlineKeyboardButton(
|
||||||
|
template.name,
|
||||||
|
callback_data=f"template:{template.id}"
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
return InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
def get_preview_keyboard() -> InlineKeyboardMarkup:
|
||||||
|
"""Возвращает клавиатуру для предпросмотра."""
|
||||||
|
keyboard = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton("✅ Отправить", callback_data="preview:send"),
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="preview:cancel")
|
||||||
|
]
|
||||||
|
]
|
||||||
|
return InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
|
||||||
class KbBuilder:
|
class KbBuilder:
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ from .handlers.templates import (
|
|||||||
handle_template_name,
|
handle_template_name,
|
||||||
handle_template_text,
|
handle_template_text,
|
||||||
handle_template_keyboard,
|
handle_template_keyboard,
|
||||||
list_templates
|
list_templates,
|
||||||
|
handle_template_selection,
|
||||||
|
handle_template_vars,
|
||||||
|
handle_preview_confirmation
|
||||||
)
|
)
|
||||||
from .handlers.posts import (
|
from .handlers.posts import (
|
||||||
newpost,
|
newpost,
|
||||||
@@ -41,7 +44,10 @@ def register_handlers(app: Application) -> None:
|
|||||||
|
|
||||||
# Шаблоны
|
# Шаблоны
|
||||||
template_handler = ConversationHandler(
|
template_handler = ConversationHandler(
|
||||||
entry_points=[CommandHandler("newtemplate", start_template_creation)],
|
entry_points=[
|
||||||
|
CommandHandler("newtemplate", start_template_creation),
|
||||||
|
CommandHandler("tpl_list", list_templates)
|
||||||
|
],
|
||||||
states={
|
states={
|
||||||
BotStates.TPL_TYPE: [
|
BotStates.TPL_TYPE: [
|
||||||
CallbackQueryHandler(handle_template_type)
|
CallbackQueryHandler(handle_template_type)
|
||||||
@@ -54,6 +60,15 @@ def register_handlers(app: Application) -> None:
|
|||||||
],
|
],
|
||||||
BotStates.TPL_NEW_KB: [
|
BotStates.TPL_NEW_KB: [
|
||||||
MessageHandler(filters.TEXT & ~filters.COMMAND, handle_template_keyboard)
|
MessageHandler(filters.TEXT & ~filters.COMMAND, handle_template_keyboard)
|
||||||
|
],
|
||||||
|
BotStates.SELECT_TEMPLATE: [
|
||||||
|
CallbackQueryHandler(handle_template_selection, pattern=r"^template:")
|
||||||
|
],
|
||||||
|
BotStates.TEMPLATE_VARS: [
|
||||||
|
MessageHandler(filters.TEXT & ~filters.COMMAND, handle_template_vars)
|
||||||
|
],
|
||||||
|
BotStates.PREVIEW_CONFIRM: [
|
||||||
|
CallbackQueryHandler(handle_preview_confirmation, pattern=r"^preview:")
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
fallbacks=[CommandHandler("cancel", cancel)]
|
fallbacks=[CommandHandler("cancel", cancel)]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class BotStates(IntEnum):
|
|||||||
TEMPLATE_PREVIEW = 19
|
TEMPLATE_PREVIEW = 19
|
||||||
TEMPLATE_VARS = 20
|
TEMPLATE_VARS = 20
|
||||||
|
|
||||||
# Состояния создания поста
|
# Состояния работы с шаблонами и создания поста
|
||||||
CREATE_POST = 30
|
CREATE_POST = 30
|
||||||
CHOOSE_CHANNEL = 31 # Выбор канала
|
CHOOSE_CHANNEL = 31 # Выбор канала
|
||||||
CHOOSE_TYPE = 32 # Выбор типа поста (текст/фото/видео/gif)
|
CHOOSE_TYPE = 32 # Выбор типа поста (текст/фото/видео/gif)
|
||||||
@@ -33,9 +33,9 @@ class BotStates(IntEnum):
|
|||||||
EDIT_KEYBOARD = 36 # Редактирование клавиатуры
|
EDIT_KEYBOARD = 36 # Редактирование клавиатуры
|
||||||
CONFIRM_SEND = 37 # Подтверждение отправки
|
CONFIRM_SEND = 37 # Подтверждение отправки
|
||||||
ENTER_SCHEDULE = 38 # Ввод времени для отложенной публикации
|
ENTER_SCHEDULE = 38 # Ввод времени для отложенной публикации
|
||||||
SELECT_TEMPLATE = 39 # Выбор шаблона
|
SELECT_TEMPLATE = 25 # Выбор шаблона
|
||||||
PREVIEW_VARS = 40 # Ввод значений для переменных
|
PREVIEW_VARS = 40 # Ввод значений для переменных
|
||||||
PREVIEW_CONFIRM = 41 # Подтверждение предпросмотра
|
PREVIEW_CONFIRM = 26 # Подтверждение предпросмотра
|
||||||
|
|
||||||
# Состояния работы с каналами
|
# Состояния работы с каналами
|
||||||
CHANNEL_NAME = 50
|
CHANNEL_NAME = 50
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ DEFAULT_TTL = 3600 # 1 час
|
|||||||
# Настройка логирования
|
# Настройка логирования
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
async def main():
|
async def run_bot():
|
||||||
"""Запуск бота."""
|
"""Запуск бота."""
|
||||||
app = Application.builder().token(settings.editor_bot_token).build()
|
app = Application.builder().token(settings.editor_bot_token).build()
|
||||||
|
|
||||||
@@ -39,23 +39,17 @@ async def main():
|
|||||||
# Запуск бота
|
# Запуск бота
|
||||||
await app.run_polling(allowed_updates=Update.ALL_TYPES)
|
await app.run_polling(allowed_updates=Update.ALL_TYPES)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def main():
|
||||||
import asyncio
|
"""Основная функция запуска."""
|
||||||
try:
|
try:
|
||||||
asyncio.run(main())
|
asyncio.run(run_bot())
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
logger.info("Бот остановлен")
|
logger.info("Бот остановлен")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Ошибка: {e}", exc_info=True)
|
logger.error(f"Ошибка: {e}", exc_info=True)
|
||||||
finally:
|
|
||||||
# Убедимся, что все циклы закрыты
|
if __name__ == "__main__":
|
||||||
loop = asyncio.get_event_loop()
|
main()
|
||||||
if loop.is_running():
|
|
||||||
loop.stop()
|
|
||||||
if not loop.is_closed():
|
|
||||||
loop.close()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка: {e}", exc_info=True)
|
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from .editor.session import SessionStore
|
from .editor.session import SessionStore
|
||||||
@@ -67,12 +61,7 @@ from .editor.handlers.templates import (
|
|||||||
handle_template_keyboard,
|
handle_template_keyboard,
|
||||||
list_templates
|
list_templates
|
||||||
)
|
)
|
||||||
from .editor.handlers.posts import (
|
from .editor.handlers.posts import newpost
|
||||||
newpost,
|
|
||||||
handle_post_template,
|
|
||||||
handle_post_channel,
|
|
||||||
handle_post_schedule
|
|
||||||
)
|
|
||||||
from .editor.states import BotStates
|
from .editor.states import BotStates
|
||||||
|
|
||||||
# Настройка логирования
|
# Настройка логирования
|
||||||
@@ -624,7 +613,7 @@ async def tpl_new_content(update: Update, context: Context) -> int:
|
|||||||
"title": session.template_name,
|
"title": session.template_name,
|
||||||
"content": content,
|
"content": content,
|
||||||
"type": session.type,
|
"type": session.type,
|
||||||
"owner_id": user.id,
|
"tg_user_id": user.id, # Передаем telegram user id вместо owner_id
|
||||||
"parse_mode": session.parse_mode,
|
"parse_mode": session.parse_mode,
|
||||||
"keyboard_tpl": session.keyboard
|
"keyboard_tpl": session.keyboard
|
||||||
}
|
}
|
||||||
@@ -633,8 +622,9 @@ async def tpl_new_content(update: Update, context: Context) -> int:
|
|||||||
await create_template(template_data)
|
await create_template(template_data)
|
||||||
await message.reply_text("Шаблон успешно сохранен")
|
await message.reply_text("Шаблон успешно сохранен")
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
except ValueError as e:
|
except Exception as e:
|
||||||
await message.reply_text(f"Ошибка создания шаблона: {e}")
|
logger.error(f"Ошибка создания шаблона: {e}", exc_info=True)
|
||||||
|
await message.reply_text(f"Ошибка создания шаблона. Пожалуйста, попробуйте позже.")
|
||||||
return BotStates.TPL_NEW_CONTENT
|
return BotStates.TPL_NEW_CONTENT
|
||||||
|
|
||||||
async def list_user_templates(update: Update, context: Context) -> None:
|
async def list_user_templates(update: Update, context: Context) -> None:
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ async def list_templates(owner_id: Optional[int] = None, limit: Optional[int] =
|
|||||||
List[Template]: Список шаблонов
|
List[Template]: Список шаблонов
|
||||||
"""
|
"""
|
||||||
async with async_session_maker() as session:
|
async with async_session_maker() as session:
|
||||||
query = Template.__table__.select()
|
query = select(Template)
|
||||||
if owner_id is not None:
|
if owner_id is not None:
|
||||||
query = query.where(Template.__table__.c.owner_id == owner_id)
|
query = query.where(Template.owner_id == owner_id)
|
||||||
if offset is not None:
|
if offset is not None:
|
||||||
query = query.offset(offset)
|
query = query.offset(offset)
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
@@ -45,6 +45,8 @@ async def list_templates(owner_id: Optional[int] = None, limit: Optional[int] =
|
|||||||
result = await session.execute(query)
|
result = await session.execute(query)
|
||||||
return list(result.scalars())
|
return list(result.scalars())
|
||||||
|
|
||||||
|
from app.services.users import get_or_create_user
|
||||||
|
|
||||||
async def create_template(template_data: Dict[str, Any]) -> Template:
|
async def create_template(template_data: Dict[str, Any]) -> Template:
|
||||||
"""Создать новый шаблон.
|
"""Создать новый шаблон.
|
||||||
|
|
||||||
@@ -54,6 +56,12 @@ async def create_template(template_data: Dict[str, Any]) -> Template:
|
|||||||
Returns:
|
Returns:
|
||||||
Template: Созданный шаблон
|
Template: Созданный шаблон
|
||||||
"""
|
"""
|
||||||
|
# Проверяем owner_id и создаем пользователя если нужно
|
||||||
|
tg_user_id = template_data.pop("tg_user_id", None)
|
||||||
|
if tg_user_id:
|
||||||
|
user = await get_or_create_user(tg_user_id)
|
||||||
|
template_data["owner_id"] = user.id
|
||||||
|
|
||||||
async with async_session_maker() as session:
|
async with async_session_maker() as session:
|
||||||
template = Template(**template_data)
|
template = Template(**template_data)
|
||||||
session.add(template)
|
session.add(template)
|
||||||
|
|||||||
30
app/services/users.py
Normal file
30
app/services/users.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
"""Сервис для работы с пользователями."""
|
||||||
|
from typing import Optional
|
||||||
|
from sqlalchemy import select
|
||||||
|
from app.db.session import async_session_maker
|
||||||
|
from app.models.user import User
|
||||||
|
|
||||||
|
async def get_or_create_user(tg_user_id: int, username: Optional[str] = None) -> User:
|
||||||
|
"""Получить или создать пользователя.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tg_user_id: ID пользователя в Telegram
|
||||||
|
username: Имя пользователя в Telegram
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
User: Объект пользователя
|
||||||
|
"""
|
||||||
|
async with async_session_maker() as session:
|
||||||
|
# Пробуем найти пользователя
|
||||||
|
query = select(User).where(User.tg_user_id == tg_user_id)
|
||||||
|
result = await session.execute(query)
|
||||||
|
user = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
# Создаем нового пользователя
|
||||||
|
user = User(tg_user_id=tg_user_id, username=username)
|
||||||
|
session.add(user)
|
||||||
|
await session.commit()
|
||||||
|
await session.refresh(user)
|
||||||
|
|
||||||
|
return user
|
||||||
Reference in New Issue
Block a user