from aiogram import F from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton from app import dp, ADMIN_ID from auth import is_admin_msg from keyboards import menu_kb HELP_PAGES = [ ( "Overview", "ℹ️ **Help — Overview**\n\n" "🩺 *Health* — быстрый health-check.\n" "📊 *Статус* — общая загрузка.\n" "📋 */status_short* — кратко (load/RAM/диски).\n" "🩺 */health_short* — краткий health.\n" "🔧 Разделы: Docker, Backup, Artifacts, System, OpenWrt.", ), ( "Alerts", "🚨 **Alerts & Mute**\n\n" "Команды:\n" "• `/alerts test `\n" "• `/alerts mute ` / `/alerts unmute ` / `/alerts list`\n" "• `/alerts recent [hours]`\n" "Шорткаты: `/alerts_list`, `/alerts_recent`, `/alerts_mute_load` (60м).\n" "Категории: load, disk, smart, ssl, docker, test.\n" "Quiet hours: `alerts.quiet_hours` для не‑критичных.\n" "Только красные load: `alerts.load_only_critical: true`.\n" "Валидатор конфига: `/config_check`.", ), ( "Backup", "💾 **Backup (restic)**\n\n" "Кнопки: Status, Last snapshot, Repo stats, Run backup, Queue, Restic check, Weekly report.\n" "Run backup/Check учитывают `safety.dry_run`.\n" "После бэкапа приходит TL;DR + путь к логу `/var/log/backup-auto.log`.\n" "Queue → Details показывает отложенные задачи.", ), ( "Docker & System", "🐳 **Docker**\n" "Status/Restart/Logs/Stats — клавиатура Docker.\n" "Команды: `/docker_status`, `/docker_health `.\n\n" "🖥 **System**\n" "Info: Disks/Security/Metrics/Hardware/SMART/OpenWrt.\n" "Ops: Updates/Upgrade/Reboot.\n" "Logs: Audit/Incidents/Security/Integrations/Processes.\n" "OpenWrt: `/openwrt`, `/openwrt_wan`, `/openwrt_clients`.", ), ( "Admin", "🛠 **Admin & Deploy**\n\n" "Config: `/config_check`, файл `config.yaml` (см. config.example.yaml).\n" "Deploy: `deploy.sh` (ssh 10.10.10.10:1090 → git pull → systemctl restart tg-bot).\n" "Безопасность: `safety.dry_run: true` блокирует опасные действия.\n" "OpenWrt: кнопка в System → Info.", ), ] def _help_kb(idx: int) -> InlineKeyboardMarkup: buttons = [] if idx > 0: buttons.append(InlineKeyboardButton(text="◀️ Prev", callback_data=f"help:{idx-1}")) buttons.append(InlineKeyboardButton(text=f"{idx+1}/{len(HELP_PAGES)}", callback_data="help:noop")) if idx < len(HELP_PAGES) - 1: buttons.append(InlineKeyboardButton(text="Next ▶️", callback_data=f"help:{idx+1}")) return InlineKeyboardMarkup(inline_keyboard=[buttons]) def _help_text(idx: int) -> str: _title, body = HELP_PAGES[idx] return body @dp.message(F.text.in_({"ℹ️ Help", "ℹ Help", "Help", "/help"})) async def help_cmd(msg: Message): if not is_admin_msg(msg): return idx = 0 await msg.answer( _help_text(idx), reply_markup=_help_kb(idx), parse_mode="Markdown", ) @dp.callback_query(F.data.startswith("help:")) async def help_cb(cb: CallbackQuery): if cb.from_user.id != ADMIN_ID: await cb.answer() return payload = cb.data.split(":", 1)[1] if payload == "noop": await cb.answer() return try: idx = int(payload) except ValueError: await cb.answer() return idx = max(0, min(idx, len(HELP_PAGES) - 1)) await cb.message.edit_text( _help_text(idx), reply_markup=_help_kb(idx), parse_mode="Markdown", ) await cb.answer()