P9(5): restore upstream Telegram bot (settings, backup, notifications)
Per user decision 2026-10-21 (reverses the 2026-10-20 drop-Telegram call): port the upstream 3x-ui v3.7.0-generation Telegram bot wholesale instead of rewriting a minimal set, adapted to this fork. - new internal/web/service/tgbot package (telego): bot lifecycle, commands, reports, callback router, send helpers; token validation via telego; custom API server URL passes the fork's SSRF sanitizer (loopback/private bases fall back to the default endpoint, logged) - settings: full upstream key set (tgBotEnable/Token/Proxy/APIServer/ ChatId, tgRunTime, tgBotBackup, tgCpu/tgMemory, tgLang, tgEnabledEvents) with getters/setters; settings page gains a Telegram tab + sidebar entry; token shown masked, clearTgBotToken honored - wiring (web.go): stats-notify cron registered from tgRunTime when the bot is enabled; CheckHashStorage job; CPU/memory alarm jobs gated on tgEnabledEvents + thresholds; login notifications via event bus; POST /panel/api/setting/testTgBot and /panel/api/backuptotgbot - lite adaptation: StatsNotifyJob no longer gates on a local Xray core (this panel never runs one) so the periodic report and the scheduled DB backup (sendDocument) can actually fire - translations: upstream TG keys restored across all locales End-to-end smoke (real binary + fake Telegram API over HTTPS at a public-looking address, browser form wire format): bot starts on settings change (getMe), testTgBot delivers, panel restart re-arms the bot, tgRunTime='@every 1m' cron really fires sendDocument carrying the panel SQLite DB (magic verified) plus the report sendMessage, login notification delivered, dead-endpoint failure is logged not silent. 13/13 PASS — see P9-REPORT.md.
This commit is contained in:
@@ -88,7 +88,8 @@
|
||||
"noExpiry": "Бессрочно",
|
||||
"copyAllConfigs": "Копировать все конфигурации",
|
||||
"copyAllConfigsCopied": "Все конфигурации скопированы",
|
||||
"email": "Email"
|
||||
"email": "Email",
|
||||
"individualLinks": "Индивидуальные ссылки"
|
||||
},
|
||||
"menu": {
|
||||
"theme": "Тема",
|
||||
@@ -1168,7 +1169,44 @@
|
||||
"httpMethodDesc": "Метод запросов при проверках.",
|
||||
"note": "Балансировщики leastPing/leastLoad всегда содержат burst-обсерваторию. Этот переключатель настраивает её параметры проб — выключите, чтобы использовать встроенные значения по умолчанию. Изменения применяются после перезапуска панели."
|
||||
}
|
||||
}
|
||||
},
|
||||
"TGBotSettings": "Telegram-бот",
|
||||
"notifications": "Уведомления",
|
||||
"notifyTime": {
|
||||
"custom": "Произвольный (crontab)",
|
||||
"daily": "@daily — каждый день в 00:00",
|
||||
"every": "@every — повторять с интервалом",
|
||||
"hourly": "@hourly — каждый час",
|
||||
"hours": "Часы",
|
||||
"interval": "Интервал",
|
||||
"minutes": "Минуты",
|
||||
"monthly": "@monthly — каждый месяц",
|
||||
"seconds": "Секунды",
|
||||
"unit": "Единица",
|
||||
"weekly": "@weekly — каждую неделю"
|
||||
},
|
||||
"telegramAPIServer": "Telegram API Server",
|
||||
"telegramAPIServerDesc": "Используемый API-сервер Telegram. Оставьте пустым, чтобы использовать сервер по умолчанию.",
|
||||
"telegramBotEnable": "Включить Telegram бота",
|
||||
"telegramBotEnableDesc": "Доступ к функциям панели через Telegram-бота",
|
||||
"telegramBotLanguage": "Язык Telegram-бота",
|
||||
"telegramChatId": "User ID администратора бота",
|
||||
"telegramChatIdDesc": "Один или несколько User ID администратора(-ов) Telegram-бота. Для получения User ID используйте {'@'}userinfobot или команду '/id' в боте.",
|
||||
"telegramNotifyTime": "Частота уведомлений для администраторов от бота",
|
||||
"telegramNotifyTimeDesc": "Как часто бот Telegram отправляет периодические отчёты. Выберите готовый интервал или «Произвольный», чтобы ввести выражение crontab.",
|
||||
"telegramToken": "Telegram-токен",
|
||||
"telegramTokenConfigured": "Настроен; оставьте пустым для сохранения текущего токена.",
|
||||
"telegramTokenDesc": "Необходимо получить токен у менеджера ботов Telegram {'@'}botfather",
|
||||
"telegramTokenPlaceholder": "Настроен - введите новый токен для замены",
|
||||
"testTgBot": "Отправить тестовое сообщение",
|
||||
"tgBotNotEnabled": "Telegram бот не включен",
|
||||
"tgBotNotRunning": "Telegram бот не запущен",
|
||||
"tgEventBusNotify": "Telegram уведомления о событиях",
|
||||
"tgEventBusNotifyDesc": "Выберите события для Telegram уведомлений",
|
||||
"tgNotifyBackup": "Резервное копирование базы данных",
|
||||
"tgNotifyBackupDesc": "Отправлять уведомление с файлом резервной копии базы данных",
|
||||
"tgTestFailed": "Тест Telegram не удался",
|
||||
"tgTestSuccess": "Тестовое сообщение отправлено в Telegram"
|
||||
},
|
||||
"xray": {
|
||||
"importRules": "Импорт правил",
|
||||
@@ -1657,7 +1695,182 @@
|
||||
}
|
||||
},
|
||||
"tgbot": {
|
||||
"noIpRecord": "❗ Нет записей об IP-адресе."
|
||||
"noIpRecord": "❗ Нет записей об IP-адресе.",
|
||||
"keyboardClosed": "❌ Клавиатура закрыта.",
|
||||
"noResult": "❗ Нет результатов.",
|
||||
"noQuery": "❌ Запрос не найден. Пожалуйста, повторите команду.",
|
||||
"wentWrong": "❌ Что-то пошло не так...",
|
||||
"noInbounds": "❗ У вас не настроено ни одного входящего подключения.",
|
||||
"unlimited": "♾ Безлимит",
|
||||
"add": "Добавить",
|
||||
"month": "Месяц",
|
||||
"months": "Месяцев",
|
||||
"days": "Дней",
|
||||
"hours": "Часов",
|
||||
"minutes": "Минуты",
|
||||
"unknown": "Неизвестно",
|
||||
"inbounds": "Входящие",
|
||||
"clients": "Клиенты",
|
||||
"offline": "🔴 Не в сети",
|
||||
"online": "🟢 В сети",
|
||||
"commands": {
|
||||
"unknown": "❗ Неизвестная команда",
|
||||
"pleaseChoose": "👇 Пожалуйста, выберите:\r\n",
|
||||
"help": "🤖 Добро пожаловать! Этот бот предназначен для предоставления вам данных с сервера и позволяет вносить изменения на него.\r\n\r\n",
|
||||
"start": "👋 Привет, <i>{{ .Firstname }}</i>.\r\n",
|
||||
"welcome": "🤖 Добро пожаловать в бота управления <b>{{ .Hostname }}</b>!\r\n",
|
||||
"status": "✅ Бот функционирует нормально.",
|
||||
"usage": "❗ Пожалуйста, укажите email для поиска.",
|
||||
"getID": "🆔 Ваш User ID: <code>{{ .ID }}</code>",
|
||||
"helpAdminCommands": "🔃 Для перезапуска Xray Core:\r\n<code>/restart</code>\r\n\r\n🔎 Для поиска клиента по email:\r\n<code>/usage [Email]</code>\r\n\r\n📊 Для поиска входящих подключений (со статистикой клиентов):\r\n<code>/inbound [имя подключения]</code>\r\n\r\n🆔 Ваш Telegram User ID:\r\n<code>/id</code>",
|
||||
"helpClientCommands": "💲 Для просмотра информации о вашей подписке используйте команду:\r\n<code>/usage [Email]</code>\r\n\r\n🆔 Ваш Telegram User ID:\r\n<code>/id</code>",
|
||||
"restartUsage": "\r\n\r\n<code>/restart</code>",
|
||||
"restartSuccess": "✅ Ядро Xray успешно перезапущено.",
|
||||
"restartFailed": "❗ Ошибка при перезапуске Xray-core.\r\n\r\n<code>Ошибка: {{ .Error }}</code>.",
|
||||
"xrayNotRunning": "❗ Xray Core не запущен.",
|
||||
"startDesc": "Показать главное меню",
|
||||
"helpDesc": "Справка по боту",
|
||||
"statusDesc": "Проверить статус бота",
|
||||
"idDesc": "Показать ваш Telegram ID",
|
||||
"usageDesc": "Показать трафик клиента: /usage email",
|
||||
"inboundDesc": "Поиск входящих: /inbound имя (админ)",
|
||||
"restartDesc": "Перезапустить ядро Xray (админ)",
|
||||
"clearallDesc": "Сбросить трафик всех клиентов (админ)"
|
||||
},
|
||||
"messages": {
|
||||
"cpuThreshold": "Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%",
|
||||
"selectUserFailed": "❌ Ошибка при выборе пользователя.",
|
||||
"userSaved": "✅ Пользователь Telegram сохранен.",
|
||||
"loginSuccess": "✅ Успешный вход в панель.\r\n",
|
||||
"loginFailed": "❗️ Ошибка входа в панель.\r\n",
|
||||
"report": "🕰 Запланированные отчеты: {{ .RunTime }}\r\n",
|
||||
"datetime": "⏰ Дата и время: {{ .DateTime }}\r\n",
|
||||
"hostname": "💻 Хост: {{ .Hostname }}\r\n",
|
||||
"version": "🚀 Версия X-UI: {{ .Version }}\r\n",
|
||||
"xrayVersion": "📡 Версия Xray: {{ .XrayVersion }}\r\n",
|
||||
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
|
||||
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
|
||||
"ip": "🌐 IP: {{ .IP }}\r\n",
|
||||
"ips": "🔢 IP:\r\n{{ .IPs }}\r\n",
|
||||
"serverUpTime": "⏳ Время работы сервера: {{ .UpTime }} {{ .Unit }}\r\n",
|
||||
"serverLoad": "📈 Нагрузка сервера: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n",
|
||||
"serverMemory": "📋 RAM: {{ .Current }}/{{ .Total }}\r\n",
|
||||
"tcpCount": "🔹 TCP: {{ .Count }}\r\n",
|
||||
"udpCount": "🔸 UDP: {{ .Count }}\r\n",
|
||||
"traffic": "🚦 Трафик: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n",
|
||||
"xrayStatus": "ℹ️ Статус: {{ .State }}\r\n",
|
||||
"username": "👤 Имя пользователя: {{ .Username }}\r\n",
|
||||
"reason": "❗️ Причина: {{ .Reason }}\r\n",
|
||||
"time": "⏰ Время: {{ .Time }}\r\n",
|
||||
"inbound": "📍 Входящий: {{ .Remark }}\r\n",
|
||||
"port": "🔌 Порт: {{ .Port }}\r\n",
|
||||
"expire": "📅 Дата окончания: {{ .Time }}\r\n",
|
||||
"expireIn": "📅 Окончание через: {{ .Time }}\r\n",
|
||||
"active": "💡 Активен: {{ .Enable }}\r\n",
|
||||
"enabled": "🚨 Активен: {{ .Enable }}\r\n",
|
||||
"online": "🌐 Статус соединения: {{ .Status }}\r\n",
|
||||
"lastOnline": "🔙 Был(а) в сети: {{ .Time }}\r\n",
|
||||
"email": "📧 Email: {{ .Email }}\r\n",
|
||||
"upload": "🔼 Загрузка: ↑{{ .Upload }}\r\n",
|
||||
"download": "🔽 Загрузка: ↓{{ .Download }}\r\n",
|
||||
"total": "📊 Всего: ↑↓{{ .UpDown }} / {{ .Total }}\r\n",
|
||||
"TGUser": "👤 Telegram User ID: {{ .TelegramID }}\r\n",
|
||||
"exhaustedCount": "🚨 Количество исчерпанных {{ .Type }}:\r\n",
|
||||
"onlinesCount": "🌐 Клиентов онлайн: {{ .Count }}\r\n",
|
||||
"disabled": "🛑 Отключено: {{ .Disabled }}\r\n",
|
||||
"depleteSoon": "🔜 Клиенты, у которых скоро исчерпание: {{ .Deplete }}\r\n\r\n",
|
||||
"backupTime": "🗄 Время резервного копирования: {{ .Time }}\r\n",
|
||||
"refreshedOn": "\r\n📋🔄 Обновлено: {{ .Time }}\r\n\r\n",
|
||||
"yes": "✅ Да",
|
||||
"no": "❌ Нет",
|
||||
"received_email": "📧📥 Email обновлен.",
|
||||
"received_comment": "💬📥 Комментарий обновлён.",
|
||||
"email_prompt": "📧 Стандартный email: {{ .ClientEmail }}\n\nВведите ваш email.",
|
||||
"comment_prompt": "💬 Стандартный комментарий: {{ .ClientComment }}\n\nВведите ваш комментарий.",
|
||||
"cancel": "❌ Процесс отменён! \n\nВы можете снова начать с /start в любое время. 🔄",
|
||||
"error_add_client": "⚠️ Ошибка:\n\n {{ .error }}",
|
||||
"using_default_value": "Используется значение по умолчанию👌",
|
||||
"incorrect_input": "Ваш ввод недействителен.\nФразы должны быть непрерывными без пробелов.\nПравильный пример: aaaaaa\nНеправильный пример: aaa aaa 🚫",
|
||||
"AreYouSure": "Вы уверены? 🤔",
|
||||
"SuccessResetTraffic": "📧 Почта: {{ .ClientEmail }}\n🏁 Результат: ✅ Успешно",
|
||||
"FailedResetTraffic": "📧 Почта: {{ .ClientEmail }}\n🏁 Результат: ❌ Неудача \n\n🛠️ Ошибка: [ {{ .ErrorMessage }} ]",
|
||||
"FinishProcess": "🔚 Сброс трафика завершён для всех клиентов.",
|
||||
"eventOutboundDown": "Исходящее подключение {{ .Tag }} НЕДОСТУПНО",
|
||||
"eventOutboundUp": "Исходящее подключение {{ .Tag }} РАБОТАЕТ",
|
||||
"eventErrorDetail": "Ошибка: {{ .Error }}",
|
||||
"eventDelayDetail": "Задержка: {{ .Delay }} мс",
|
||||
"eventXrayCrash": "Сбой Xray",
|
||||
"eventXrayCrashError": "Ошибка: {{ .Error }}",
|
||||
"eventNodeDown": "Узел {{ .Name }} НЕДОСТУПЕН",
|
||||
"eventNodeUp": "Узел {{ .Name }} В СЕТИ",
|
||||
"eventLoginFallback": "Неудачный вход с {{ .Source }}",
|
||||
"memoryThreshold": "🔴 Использование памяти {{ .Percent }}% превышает пороговое значение {{ .Threshold }}%"
|
||||
},
|
||||
"buttons": {
|
||||
"closeKeyboard": "❌ Закрыть клавиатуру",
|
||||
"cancel": "❌ Отмена",
|
||||
"cancelReset": "❌ Отменить сброс",
|
||||
"cancelIpLimit": "❌ Отменить лимит IP",
|
||||
"confirmResetTraffic": "✅ Подтвердить сброс трафика?",
|
||||
"confirmClearIps": "✅ Подтвердить очистку IP?",
|
||||
"confirmRemoveTGUser": "✅ Подтвердить удаление пользователя Telegram?",
|
||||
"confirmToggle": "✅ Подтвердить вкл/выкл пользователя?",
|
||||
"dbBackup": "📂 Бэкап БД",
|
||||
"serverUsage": "💻 Состояние сервера",
|
||||
"getInbounds": "🔌 Входящие подключения",
|
||||
"depleteSoon": "⚠️ Скоро конец",
|
||||
"clientUsage": "Статистика клиента",
|
||||
"onlines": "🟢 Онлайн",
|
||||
"commands": "🖱️ Команды",
|
||||
"refresh": "🔄 Обновить",
|
||||
"clearIPs": "❌ Очистить IP",
|
||||
"removeTGUser": "❌ Удалить пользователя Telegram",
|
||||
"selectTGUser": "👤 Выбрать пользователя Telegram",
|
||||
"selectOneTGUser": "👤 Выберите пользователя Telegram:",
|
||||
"resetTraffic": "📈 Сбросить трафик",
|
||||
"resetExpire": "📅 Изменить дату окончания",
|
||||
"ipLog": "🔢 Лог IP",
|
||||
"ipLimit": "🔢 Лимит IP",
|
||||
"setTGUser": "👤 Установить пользователя Telegram",
|
||||
"toggle": "🔘 Вкл./Выкл.",
|
||||
"custom": "🔢 Своё",
|
||||
"confirmNumber": "✅ Подтвердить: {{ .Num }}",
|
||||
"confirmNumberAdd": "✅ Подтвердить добавление: {{ .Num }}",
|
||||
"limitTraffic": "🚧 Лимит трафика",
|
||||
"getBanLogs": "📄 Лог банов",
|
||||
"allClients": "👥 Все клиенты",
|
||||
"addClient": "➕ Новый клиент",
|
||||
"submitDisable": "Добавить отключенным ☑️",
|
||||
"submitEnable": "Добавить включенным ✅",
|
||||
"use_default": "🏷️ Использовать по умолчанию",
|
||||
"change_email": "⚙️📧 Email",
|
||||
"change_comment": "⚙️💬 Комментарий",
|
||||
"ResetAllTraffics": "Сбросить весь трафик",
|
||||
"SortedTrafficUsageReport": "Отсортированный отчет об использовании трафика"
|
||||
},
|
||||
"answers": {
|
||||
"successfulOperation": "✅ Успешно!",
|
||||
"errorOperation": "❗ Ошибка в операции.",
|
||||
"getInboundsFailed": "❌ Не удалось получить входящие подключения.",
|
||||
"getClientsFailed": "❌ Не удалось получить клиентов.",
|
||||
"canceled": "❌ {{ .Email }}: Операция отменена.",
|
||||
"clientRefreshSuccess": "✅ {{ .Email }}: Клиент успешно обновлен.",
|
||||
"IpRefreshSuccess": "✅ {{ .Email }}: IP-адреса успешно обновлены.",
|
||||
"TGIdRefreshSuccess": "✅ {{ .Email }}: Пользователь Telegram клиента успешно обновлен.",
|
||||
"resetTrafficSuccess": "✅ {{ .Email }}: Трафик успешно сброшен.",
|
||||
"setTrafficLimitSuccess": "✅ {{ .Email }}: Лимит трафика успешно установлен.",
|
||||
"expireResetSuccess": "✅ {{ .Email }}: Срок действия успешно сброшен.",
|
||||
"resetIpSuccess": "✅ {{ .Email }}: Лимит IP ({{ .Count }}) успешно сохранен.",
|
||||
"clearIpSuccess": "✅ {{ .Email }}: IP-адреса успешно очищены.",
|
||||
"getIpLog": "✅ {{ .Email }}: Получен лог IP.",
|
||||
"getUserInfo": "✅ {{ .Email }}: Получена информация о пользователе Telegram.",
|
||||
"removedTGUserSuccess": "✅ {{ .Email }}: Пользователь Telegram успешно удален.",
|
||||
"enableSuccess": "✅ {{ .Email }}: Включено успешно.",
|
||||
"disableSuccess": "✅ {{ .Email }}: Отключено успешно.",
|
||||
"askToAddUserId": "❌ Ваша конфигурация не найдена!\r\n💭 Пожалуйста, попросите администратора использовать ваш Telegram User ID в конфигурации.\r\n\r\n🆔 Ваш User ID: <code>{{ .TgUserID }}</code>",
|
||||
"chooseClient": "Выберите клиента для входящего подключения {{ .Inbound }}",
|
||||
"chooseInbound": "Выберите входящее подключение"
|
||||
}
|
||||
},
|
||||
"email": {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user