Add project files
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BotConfig(AppConfig):
|
||||
name = 'bot'
|
||||
@@ -0,0 +1,85 @@
|
||||
# bot/handlers.py
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
from django.utils import translation
|
||||
from django.utils.translation import gettext as _
|
||||
from .utils import render_keyboard, render_message
|
||||
from .router import router
|
||||
|
||||
# 1. Сценарий: Меню
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
# Установка языка по умолчанию
|
||||
context.user_data['lang'] = 'ru'
|
||||
|
||||
keyboard = render_keyboard('bot/menu.html')
|
||||
text = _("Добро пожаловать! Выберите действие:")
|
||||
|
||||
await update.message.reply_text(text, reply_markup=keyboard)
|
||||
|
||||
# Обработчики callback-ов через наш роутер
|
||||
|
||||
@router.route('set_lang')
|
||||
async def set_language_menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
# Показываем меню выбора языка
|
||||
keyboard = render_keyboard('bot/lang_menu.html')
|
||||
await update.callback_query.edit_message_text(
|
||||
_("Выберите язык интерфейса:"),
|
||||
reply_markup=keyboard
|
||||
)
|
||||
|
||||
@router.route('lang_ru')
|
||||
async def lang_ru(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
context.user_data['lang'] = 'ru'
|
||||
translation.activate('ru')
|
||||
await show_main_menu(update, _("Язык сменен на Русский"))
|
||||
|
||||
@router.route('lang_en')
|
||||
async def lang_en(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
context.user_data['lang'] = 'en'
|
||||
translation.activate('en')
|
||||
await show_main_menu(update, _("Language changed to English"))
|
||||
|
||||
@router.route('lang_fr')
|
||||
async def lang_fr(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
context.user_data['lang'] = 'fr'
|
||||
translation.activate('fr')
|
||||
await show_main_menu(update, _("Язык сменен на Французский"))
|
||||
|
||||
@router.route('lang_de')
|
||||
async def lang_de(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
context.user_data['lang'] = 'de'
|
||||
translation.activate('de')
|
||||
await show_main_menu(update, _("Язык сменен на Немецкий"))
|
||||
|
||||
@router.route('profile')
|
||||
async def profile(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
user = update.effective_user
|
||||
text = _("Ваш профиль:\nID: {id}\nИмя: {name}").format(id=user.id, name=user.first_name)
|
||||
|
||||
keyboard = render_keyboard('bot/back.html')
|
||||
await update.callback_query.edit_message_text(text, reply_markup=keyboard)
|
||||
|
||||
@router.route('help')
|
||||
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
# Текст помощи (можно тоже вынести в HTML, но для простоты тут текст)
|
||||
text = _("ℹ️ *Справка*\n\n"
|
||||
"Это демонстрационный бот на Django.\n"
|
||||
"Вы можете менять язык интерфейса и смотреть профиль.\n\n"
|
||||
"Версия: 1.0")
|
||||
|
||||
# Используем кнопку "Назад", которая у нас уже есть
|
||||
keyboard = render_keyboard('bot/back.html')
|
||||
|
||||
await update.callback_query.edit_message_text(
|
||||
text,
|
||||
reply_markup=keyboard,
|
||||
parse_mode='Markdown'
|
||||
)
|
||||
|
||||
@router.route('main_menu')
|
||||
async def back_to_main(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
await show_main_menu(update, _("Главное меню"))
|
||||
|
||||
async def show_main_menu(update, text):
|
||||
keyboard = render_keyboard('bot/menu.html')
|
||||
await update.callback_query.edit_message_text(text, reply_markup=keyboard)
|
||||
@@ -0,0 +1,28 @@
|
||||
# bot/management/commands/runbot.py
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
from telegram.ext import ApplicationBuilder, CommandHandler, CallbackQueryHandler
|
||||
from bot.handlers import start, router
|
||||
import logging
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Запускает Telegram бота'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Логирование для отладки
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO
|
||||
)
|
||||
|
||||
print("Starting bot...")
|
||||
|
||||
application = ApplicationBuilder().token(settings.TELEGRAM_TOKEN).build()
|
||||
|
||||
# Регистрация хендлеров
|
||||
application.add_handler(CommandHandler("start", start))
|
||||
|
||||
# Все callback-и идут в наш роутер
|
||||
application.add_handler(CallbackQueryHandler(router.handle))
|
||||
|
||||
application.run_polling()
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
@@ -0,0 +1,44 @@
|
||||
import logging
|
||||
from django.utils import translation
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class CallbackRouter:
|
||||
def __init__(self):
|
||||
self.routes = {}
|
||||
|
||||
def route(self, pattern):
|
||||
"""Декоратор для регистрации обработчика callback"""
|
||||
def decorator(func):
|
||||
self.routes[pattern] = func
|
||||
return func
|
||||
return decorator
|
||||
|
||||
async def handle(self, update, context):
|
||||
query = update.callback_query
|
||||
await query.answer()
|
||||
|
||||
data = query.data
|
||||
# Простой протокол: "action:payload"
|
||||
action = data.split(':')[0]
|
||||
|
||||
handler = self.routes.get(action)
|
||||
if handler:
|
||||
# Берем язык из данных пользователя (по умолчанию ru)
|
||||
user_lang = context.user_data.get('lang', 'ru')
|
||||
translation.activate(user_lang)
|
||||
|
||||
try:
|
||||
await handler(update, context)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in handler {action}: {e}")
|
||||
finally:
|
||||
translation.deactivate()
|
||||
else:
|
||||
try:
|
||||
await query.edit_message_text("Неизвестная команда / Unknown command")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Глобальный объект роутера, который мы импортируем в handlers.py
|
||||
router = CallbackRouter()
|
||||
@@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
<ul>
|
||||
<li><a href="main_menu">🔙 {% trans "Вернуться в меню" %}</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,8 @@
|
||||
{% load i18n %}
|
||||
<ul>
|
||||
<li><a href="lang_ru">🇷🇺 Русский</a></li>
|
||||
<li><a href="lang_en">🇺🇸 English</a></li>
|
||||
<li><a href="lang_fr">🇫🇷 Français</a></li>
|
||||
<li><a href="lang_de">🇩🇪 Deutsch</a></li>
|
||||
<li><a href="main_menu">🔙 {% trans "Назад" %}</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,10 @@
|
||||
{% load i18n %}
|
||||
<ul>
|
||||
<li>
|
||||
<a href="profile">{% trans "👤 Профиль" %}</a>
|
||||
<a href="set_lang">{% trans "🌐 Язык" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="help">{% trans "ℹ️ Помощь" %}</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1,40 @@
|
||||
from bs4 import BeautifulSoup
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
def render_keyboard(template_name, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
html_content = render_to_string(template_name, context)
|
||||
soup = BeautifulSoup(html_content, 'html.parser')
|
||||
keyboard = []
|
||||
|
||||
# Если есть списки <li>, считаем их строками
|
||||
rows = soup.find_all('li')
|
||||
if not rows:
|
||||
# Если списков нет, собираем все ссылки в одну строку
|
||||
buttons = []
|
||||
for a in soup.find_all('a'):
|
||||
text = a.get_text(strip=True)
|
||||
callback_data = a.get('href')
|
||||
buttons.append(InlineKeyboardButton(text=text, callback_data=callback_data))
|
||||
if buttons:
|
||||
keyboard.append(buttons)
|
||||
else:
|
||||
for row in rows:
|
||||
row_buttons = []
|
||||
for a in row.find_all('a'):
|
||||
text = a.get_text(strip=True)
|
||||
callback_data = a.get('href')
|
||||
row_buttons.append(InlineKeyboardButton(text=text, callback_data=callback_data))
|
||||
if row_buttons:
|
||||
keyboard.append(row_buttons)
|
||||
|
||||
return InlineKeyboardMarkup(keyboard)
|
||||
|
||||
def render_message(template_name, context=None):
|
||||
html_content = render_to_string(template_name, context)
|
||||
soup = BeautifulSoup(html_content, 'html.parser')
|
||||
for tag in soup.find_all(['ul', 'li', 'a']):
|
||||
tag.decompose()
|
||||
return soup.get_text(separator='\n', strip=True)
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
Reference in New Issue
Block a user