Files
Solo_bot/handlers/admin/settings/settings_web.py
T
2026-05-06 20:47:53 +00:00

219 lines
8.7 KiB
Python

from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
from aiogram.utils.keyboard import InlineKeyboardBuilder
from core.settings.web_config import WEB_CONFIG, update_web_config
from database import async_session_maker
from handlers.buttons import BACK
from ..panel.keyboard import AdminPanelCallback, build_admin_back_btn
router = Router(name="admin_settings_web")
class WebSettingsState(StatesGroup):
waiting_for_url = State()
def build_settings_web_kb() -> InlineKeyboardBuilder:
builder = InlineKeyboardBuilder()
enabled = bool(WEB_CONFIG.get("WEB_ENABLED", False))
url = str(WEB_CONFIG.get("SITE_URL") or "не указан")
builder.row(
InlineKeyboardButton(
text=f"{'' if enabled else ''} Сайт {'включён' if enabled else 'выключен'}",
callback_data=AdminPanelCallback(action="settings_web_toggle").pack(),
)
)
builder.row(
InlineKeyboardButton(
text=f"🌐 URL: {url}",
callback_data=AdminPanelCallback(action="settings_web_url").pack(),
)
)
email_binding = bool(WEB_CONFIG.get("EMAIL_BINDING_ENABLED", False))
builder.row(
InlineKeyboardButton(
text=f"{'' if email_binding else ''} Привязка почты {'включена' if email_binding else 'выключена'}",
callback_data=AdminPanelCallback(action="settings_web_email_binding_toggle").pack(),
)
)
builder.row(
InlineKeyboardButton(
text="🔄 Сбросить сайт к исходнику",
callback_data=AdminPanelCallback(action="settings_web_reset_ask").pack(),
)
)
builder.row(build_admin_back_btn("settings"))
return builder
def _web_settings_text() -> str:
enabled = bool(WEB_CONFIG.get("WEB_ENABLED", False))
url = str(WEB_CONFIG.get("SITE_URL") or "не указан")
email_binding = bool(WEB_CONFIG.get("EMAIL_BINDING_ENABLED", False))
return (
"<b>🌐 Настройки веб-сайта</b>\n\n"
f"Статус: {'✅ Включён' if enabled else '❌ Выключен'}\n"
f"URL: <code>{url}</code>\n"
f"Привязка почты: {'✅ Включена' if email_binding else '❌ Выключена'}\n\n"
"Сайт может работать на отдельном домене и сервере.\n"
"При выключении кнопка «Личный кабинет» скрывается из бота.\n"
"Привязка почты — кнопка в боте, через которую пользователь указывает email "
"для входа на сайт на случай проблем с Telegram."
)
@router.callback_query(AdminPanelCallback.filter(F.action == "settings_web"))
async def open_web_settings(callback: CallbackQuery) -> None:
await callback.message.edit_text(
text=_web_settings_text(),
reply_markup=build_settings_web_kb().as_markup(),
)
await callback.answer()
@router.callback_query(AdminPanelCallback.filter(F.action == "settings_web_toggle"))
async def toggle_web_enabled(callback: CallbackQuery) -> None:
current = bool(WEB_CONFIG.get("WEB_ENABLED", False))
new_config = dict(WEB_CONFIG)
new_config["WEB_ENABLED"] = not current
async with async_session_maker() as session:
await update_web_config(session, new_config)
status = "✅ Сайт включён" if new_config["WEB_ENABLED"] else "❌ Сайт выключен"
await callback.answer(status, show_alert=True)
await callback.message.edit_text(
text=_web_settings_text(),
reply_markup=build_settings_web_kb().as_markup(),
)
@router.callback_query(AdminPanelCallback.filter(F.action == "settings_web_email_binding_toggle"))
async def toggle_email_binding(callback: CallbackQuery) -> None:
current = bool(WEB_CONFIG.get("EMAIL_BINDING_ENABLED", False))
new_config = dict(WEB_CONFIG)
new_config["EMAIL_BINDING_ENABLED"] = not current
async with async_session_maker() as session:
await update_web_config(session, new_config)
status = "✅ Привязка почты включена" if new_config["EMAIL_BINDING_ENABLED"] else "❌ Привязка почты выключена"
await callback.answer(status, show_alert=True)
await callback.message.edit_text(
text=_web_settings_text(),
reply_markup=build_settings_web_kb().as_markup(),
)
@router.callback_query(AdminPanelCallback.filter(F.action == "settings_web_url"))
async def prompt_web_url(callback: CallbackQuery, state: FSMContext) -> None:
current = str(WEB_CONFIG.get("SITE_URL") or "")
text = (
"<b>🌐 Введите URL сайта</b>\n\n"
f"Текущий: <code>{current or 'не указан'}</code>\n\n"
"Отправьте полный URL (с https://).\n"
"Пример: <code>https://my-vpn.com</code>\n\n"
"Отправьте <code>-</code> чтобы очистить."
)
await callback.message.edit_text(text=text)
await state.set_state(WebSettingsState.waiting_for_url)
await callback.answer()
@router.callback_query(AdminPanelCallback.filter(F.action == "settings_web_reset_ask"))
async def ask_reset_site(callback: CallbackQuery) -> None:
text = (
"<b>⚠️ Сброс сайта к исходнику</b>\n\n"
"Действие удалит:\n"
"• все страницы, блоки, темы и варианты\n"
"• всех веб-пользователей (включая админа сайта)\n"
"• флаг «сайт проинициализирован»\n\n"
"Биллинг-данные (пользователи бота, ключи, платежи) не трогаются.\n\n"
"После сброса админ сайта пересоздаётся из переменных окружения "
"<code>WEB_ADMIN_LOGIN</code> / <code>WEB_ADMIN_PASSWORD</code>.\n\n"
"<b>Действие необратимо.</b>"
)
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(
text="❌ Отмена",
callback_data=AdminPanelCallback(action="settings_web").pack(),
)
)
builder.row(
InlineKeyboardButton(
text="⚠️ Да, сбросить сайт",
callback_data=AdminPanelCallback(action="settings_web_reset_do").pack(),
)
)
await callback.message.edit_text(text=text, reply_markup=builder.as_markup())
await callback.answer()
@router.callback_query(AdminPanelCallback.filter(F.action == "settings_web_reset_do"))
async def do_reset_site(callback: CallbackQuery, session=None) -> None:
await callback.answer()
await callback.message.edit_text(text="<b>⏳ Сбрасываю сайт...</b>")
from middlewares.session import release_session_early
from services.site_reset import reset_site
if session is not None:
await release_session_early(session)
try:
async with async_session_maker() as s:
await reset_site(s)
await s.commit()
except Exception as exc:
from html import escape as html_escape
safe = html_escape(str(exc))[:2000]
await callback.message.edit_text(
text=f"<b>❌ Не удалось сбросить сайт</b>\n\n<code>{safe}</code>",
reply_markup=build_settings_web_kb().as_markup(),
)
return
text = (
"<b>✅ Сайт сброшен к исходнику</b>\n\n"
"Все веб-страницы, блоки и темы удалены. Админ пересоздан из env.\n"
"Откройте сайт и пройдите путь первой установки заново."
)
await callback.message.edit_text(
text=text,
reply_markup=build_settings_web_kb().as_markup(),
)
@router.message(WebSettingsState.waiting_for_url)
async def set_web_url(message: Message, state: FSMContext) -> None:
url = message.text.strip() if message.text else ""
if url == "-":
url = ""
elif url and not url.startswith("http"):
await message.answer("❌ URL должен начинаться с http:// или https://")
return
url = url.rstrip("/")
new_config = dict(WEB_CONFIG)
new_config["SITE_URL"] = url
async with async_session_maker() as session:
await update_web_config(session, new_config)
await state.clear()
await message.answer(
text=_web_settings_text(),
reply_markup=build_settings_web_kb().as_markup(),
)