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": "電子郵件",
|
||||
"individualLinks": "個別連結"
|
||||
},
|
||||
"menu": {
|
||||
"theme": "主題",
|
||||
@@ -1168,7 +1169,44 @@
|
||||
"httpMethodDesc": "探活請求使用的 HTTP 方法。",
|
||||
"note": "leastPing/leastLoad 平衡器始終帶有 burstObservatory。此開關自訂其探活參數 — 關閉以使用內建預設值。變更在面板重啟後生效。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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 伺服器",
|
||||
"telegramAPIServerDesc": "要使用的 Telegram API 伺服器。留空以使用預設伺服器。",
|
||||
"telegramBotEnable": "啟用 Telegram 機器人",
|
||||
"telegramBotEnableDesc": "啟用 Telegram 機器人功能",
|
||||
"telegramBotLanguage": "Telegram 機器人語言",
|
||||
"telegramChatId": "管理員聊天 ID",
|
||||
"telegramChatIdDesc": "Telegram 管理員聊天 ID (多個以逗號分隔)(可通過 {'@'}userinfobot 獲取,或在機器人中使用 '/id' 命令獲取)",
|
||||
"telegramNotifyTime": "通知時間",
|
||||
"telegramNotifyTimeDesc": "Telegram 機器人傳送週期性報告的頻率。選擇預設間隔,或選擇「自訂」以輸入 crontab 運算式。",
|
||||
"telegramToken": "Telegram Token",
|
||||
"telegramTokenConfigured": "已設定;留空以保留目前的權杖。",
|
||||
"telegramTokenDesc": "從 '{'@'}BotFather' 獲取的 Telegram 機器人令牌",
|
||||
"telegramTokenPlaceholder": "已設定 - 輸入新權杖以取代",
|
||||
"testTgBot": "傳送測試訊息",
|
||||
"tgBotNotEnabled": "Telegram 機器人未啟用",
|
||||
"tgBotNotRunning": "Telegram 機器人未執行",
|
||||
"tgEventBusNotify": "Telegram 事件通知",
|
||||
"tgEventBusNotifyDesc": "選擇觸發 Telegram 通知的事件",
|
||||
"tgNotifyBackup": "資料庫備份",
|
||||
"tgNotifyBackupDesc": "傳送帶有報告的資料庫備份檔案",
|
||||
"tgTestFailed": "Telegram 測試失敗",
|
||||
"tgTestSuccess": "測試訊息已傳送至 Telegram"
|
||||
},
|
||||
"xray": {
|
||||
"save": "儲存",
|
||||
@@ -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": "❗ 請輸入要搜尋的文字!",
|
||||
"getID": "🆔 您的 ID 為:<code>{{ .ID }}</code>",
|
||||
"helpAdminCommands": "要重新啟動 Xray Core:\r\n<code>/restart</code>\r\n\r\n要搜尋客戶電子郵件:\r\n<code>/usage [電子郵件]</code>\r\n\r\n要搜尋入站(帶有客戶統計資料):\r\n<code>/inbound [備註]</code>\r\n\r\nTelegram 聊天 ID:\r\n<code>/id</code>",
|
||||
"helpClientCommands": "要搜尋統計資料,請使用以下命令:\r\n<code>/usage [電子郵件]</code>\r\n\r\nTelegram 聊天 ID:\r\n<code>/id</code>",
|
||||
"restartUsage": "\r\n\r\n<code>/restart</code>",
|
||||
"restartSuccess": "✅ 操作成功!",
|
||||
"restartFailed": "❗ 操作錯誤。\r\n\r\n<code>錯誤: {{ .Error }}</code>.",
|
||||
"xrayNotRunning": "❗ Xray Core 未運行。",
|
||||
"startDesc": "顯示主選單",
|
||||
"helpDesc": "機器人幫助",
|
||||
"statusDesc": "檢查機器人狀態",
|
||||
"idDesc": "顯示您的 Telegram ID",
|
||||
"usageDesc": "查看客戶端用量:/usage 郵箱",
|
||||
"inboundDesc": "搜尋入站:/inbound 備註(管理員)",
|
||||
"restartDesc": "重啟 Xray 核心(管理員)",
|
||||
"clearallDesc": "重置所有客戶端流量(管理員)"
|
||||
},
|
||||
"messages": {
|
||||
"cpuThreshold": "CPU 使用率為 {{ .Percent }}%,超過閾值 {{ .Threshold }}%",
|
||||
"selectUserFailed": "❌ 使用者選擇錯誤!",
|
||||
"userSaved": "✅ 電報使用者已儲存。",
|
||||
"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": "🔢 IPs:\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 }}\r\n",
|
||||
"upload": "🔼 上傳: ↑{{ .Upload }}\r\n",
|
||||
"download": "🔽 下載: ↓{{ .Download }}\r\n",
|
||||
"total": "📊 總計: ↑↓{{ .UpDown }} / {{ .Total }}\r\n",
|
||||
"TGUser": "👤 電報使用者:{{ .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": "📧📥 電子郵件已更新。",
|
||||
"received_comment": "💬📥 評論已更新。",
|
||||
"email_prompt": "📧 預設電子郵件: {{ .ClientEmail }}\n\n請輸入您的電子郵件。",
|
||||
"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": "⚙️📧 電子郵件",
|
||||
"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 使用者 ChatID。\r\n\r\n您的使用者 ChatID:<code>{{ .TgUserID }}</code>",
|
||||
"chooseClient": "為入站 {{ .Inbound }} 選擇一個客戶",
|
||||
"chooseInbound": "選擇一個入站"
|
||||
}
|
||||
},
|
||||
"email": {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user