Add project files

This commit is contained in:
Nika
2025-12-29 04:26:49 +03:00
parent ace5cf9e70
commit 32e797bce7
26 changed files with 602 additions and 0 deletions
View File
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class BotConfig(AppConfig):
name = 'bot'
+85
View File
@@ -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)
View File
View File
+28
View File
@@ -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()
View File
+3
View File
@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.
+44
View File
@@ -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()
+4
View File
@@ -0,0 +1,4 @@
{% load i18n %}
<ul>
<li><a href="main_menu">🔙 {% trans "Вернуться в меню" %}</a></li>
</ul>
+8
View File
@@ -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>
+10
View File
@@ -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>
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+40
View File
@@ -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)
+3
View File
@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.