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 @@
|
||||
"unlimited": "Unlimited",
|
||||
"noExpiry": "No expiry",
|
||||
"copyAllConfigs": "Copy All Configs",
|
||||
"copyAllConfigsCopied": "All configs copied"
|
||||
"copyAllConfigsCopied": "All configs copied",
|
||||
"individualLinks": "Individual links"
|
||||
},
|
||||
"menu": {
|
||||
"theme": "Theme",
|
||||
@@ -1286,7 +1287,44 @@
|
||||
"httpMethodDesc": "Method used for probe requests.",
|
||||
"note": "leastPing/leastLoad balancers always carry a burst observatory. This switch customises its probe parameters — turn it off to use the built-in defaults. Changes apply after a panel restart."
|
||||
}
|
||||
}
|
||||
},
|
||||
"TGBotSettings": "Telegram Bot",
|
||||
"notifications": "Notifications",
|
||||
"notifyTime": {
|
||||
"custom": "Custom (crontab)",
|
||||
"daily": "@daily — every day at 00:00",
|
||||
"every": "@every — repeat at an interval",
|
||||
"hourly": "@hourly — every hour",
|
||||
"hours": "Hours",
|
||||
"interval": "Interval",
|
||||
"minutes": "Minutes",
|
||||
"monthly": "@monthly — every month",
|
||||
"seconds": "Seconds",
|
||||
"unit": "Unit",
|
||||
"weekly": "@weekly — every week"
|
||||
},
|
||||
"telegramAPIServer": "Telegram API Server",
|
||||
"telegramAPIServerDesc": "The Telegram API server to use. Leave blank to use the default server.",
|
||||
"telegramBotEnable": "Enable Telegram Bot",
|
||||
"telegramBotEnableDesc": "Enables the Telegram bot.",
|
||||
"telegramBotLanguage": "Telegram Bot Language",
|
||||
"telegramChatId": "Admin Chat ID",
|
||||
"telegramChatIdDesc": "The Telegram Admin Chat ID(s). (comma-separated)(get it here {'@'}userinfobot) or (use '/id' command in the bot)",
|
||||
"telegramNotifyTime": "Notification Time",
|
||||
"telegramNotifyTimeDesc": "How often the Telegram bot sends periodic reports. Pick a preset interval, or choose Custom to enter a raw crontab expression.",
|
||||
"telegramToken": "Telegram Token",
|
||||
"telegramTokenConfigured": "Configured; leave blank to keep current token.",
|
||||
"telegramTokenDesc": "The Telegram bot token obtained from '{'@'}BotFather'.",
|
||||
"telegramTokenPlaceholder": "Configured - enter a new token to replace",
|
||||
"testTgBot": "Send Test Message",
|
||||
"tgBotNotEnabled": "Telegram bot is not enabled",
|
||||
"tgBotNotRunning": "Telegram bot not running",
|
||||
"tgEventBusNotify": "Telegram Event Notifications",
|
||||
"tgEventBusNotifyDesc": "Select which events trigger Telegram notifications",
|
||||
"tgNotifyBackup": "Database Backup",
|
||||
"tgNotifyBackupDesc": "Send a database backup file with a report.",
|
||||
"tgTestFailed": "Telegram test failed",
|
||||
"tgTestSuccess": "Test message sent to Telegram"
|
||||
},
|
||||
"xray": {
|
||||
"save": "Save",
|
||||
@@ -1657,7 +1695,182 @@
|
||||
}
|
||||
},
|
||||
"tgbot": {
|
||||
"noIpRecord": "❗ No IP Record!"
|
||||
"noIpRecord": "❗ No IP Record!",
|
||||
"keyboardClosed": "❌ Custom keyboard closed!",
|
||||
"noResult": "❗ No result!",
|
||||
"noQuery": "❌ Query not found! Please use the command again!",
|
||||
"wentWrong": "❌ Something went wrong!",
|
||||
"noInbounds": "❗ No inbound found!",
|
||||
"unlimited": "♾ Unlimited(Reset)",
|
||||
"add": "Add",
|
||||
"month": "Month",
|
||||
"months": "Months",
|
||||
"days": "Days",
|
||||
"hours": "Hours",
|
||||
"minutes": "Minutes",
|
||||
"unknown": "Unknown",
|
||||
"inbounds": "Inbounds",
|
||||
"clients": "Clients",
|
||||
"offline": "🔴 Offline",
|
||||
"online": "🟢 Online",
|
||||
"commands": {
|
||||
"unknown": "❗ Unknown command.",
|
||||
"pleaseChoose": "👇 Please choose:\r\n",
|
||||
"help": "🤖 Welcome to this bot! It's designed to offer specific data from the web panel and allows you to make modifications as needed.\r\n\r\n",
|
||||
"start": "👋 Hello <i>{{ .Firstname }}</i>.\r\n",
|
||||
"welcome": "🤖 Welcome to <b>{{ .Hostname }}</b> management bot.\r\n",
|
||||
"status": "✅ Bot is OK!",
|
||||
"usage": "❗ Please provide a text to search!",
|
||||
"getID": "🆔 Your ID: <code>{{ .ID }}</code>",
|
||||
"helpAdminCommands": "To restart Xray Core:\r\n<code>/restart</code>\r\n\r\nTo search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nTo search for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>",
|
||||
"helpClientCommands": "To search for statistics, use the following command:\r\n\r\n<code>/usage [Email]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>",
|
||||
"restartUsage": "\r\n\r\n<code>/restart</code>",
|
||||
"restartSuccess": "✅ Operation successful!",
|
||||
"restartFailed": "❗ Error in operation.\r\n\r\n<code>Error: {{ .Error }}</code>.",
|
||||
"xrayNotRunning": "❗ Xray Core is not running.",
|
||||
"startDesc": "Show the main menu",
|
||||
"helpDesc": "Bot help",
|
||||
"statusDesc": "Check bot status",
|
||||
"idDesc": "Show your Telegram ID",
|
||||
"usageDesc": "Show client usage: /usage email",
|
||||
"inboundDesc": "Search inbounds: /inbound remark (admin)",
|
||||
"restartDesc": "Restart Xray core (admin)",
|
||||
"clearallDesc": "Reset all clients' traffic (admin)"
|
||||
},
|
||||
"messages": {
|
||||
"cpuThreshold": "CPU Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%",
|
||||
"selectUserFailed": "❌ Error in user selection!",
|
||||
"userSaved": "✅ Telegram User saved.",
|
||||
"loginSuccess": "✅ Logged in to the panel successfully.\r\n",
|
||||
"loginFailed": "❗️Login attempt to the panel failed.\r\n",
|
||||
"report": "🕰 Scheduled Reports: {{ .RunTime }}\r\n",
|
||||
"datetime": "⏰ Date&Time: {{ .DateTime }}\r\n",
|
||||
"hostname": "💻 Host: {{ .Hostname }}\r\n",
|
||||
"version": "🚀 3X-UI Version: {{ .Version }}\r\n",
|
||||
"xrayVersion": "📡 Xray Version: {{ .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: {{ .UpTime }} {{ .Unit }}\r\n",
|
||||
"serverLoad": "📈 System Load: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n",
|
||||
"serverMemory": "📋 RAM: {{ .Current }}/{{ .Total }}\r\n",
|
||||
"tcpCount": "🔹 TCP: {{ .Count }}\r\n",
|
||||
"udpCount": "🔸 UDP: {{ .Count }}\r\n",
|
||||
"traffic": "🚦 Traffic: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n",
|
||||
"xrayStatus": "ℹ️ Status: {{ .State }}\r\n",
|
||||
"username": "👤 Username: {{ .Username }}\r\n",
|
||||
"reason": "❗️ Reason: {{ .Reason }}\r\n",
|
||||
"time": "⏰ Time: {{ .Time }}\r\n",
|
||||
"inbound": "📍 Inbound: {{ .Remark }}\r\n",
|
||||
"port": "🔌 Port: {{ .Port }}\r\n",
|
||||
"expire": "📅 Expire Date: {{ .Time }}\r\n",
|
||||
"expireIn": "📅 Expire In: {{ .Time }}\r\n",
|
||||
"active": "💡 Active: {{ .Enable }}\r\n",
|
||||
"enabled": "🚨 Enabled: {{ .Enable }}\r\n",
|
||||
"online": "🌐 Connection status: {{ .Status }}\r\n",
|
||||
"lastOnline": "🔙 Last online: {{ .Time }}\r\n",
|
||||
"email": "📧 Email: {{ .Email }}\r\n",
|
||||
"upload": "🔼 Upload: ↑{{ .Upload }}\r\n",
|
||||
"download": "🔽 Download: ↓{{ .Download }}\r\n",
|
||||
"total": "📊 Total: ↑↓{{ .UpDown }} / {{ .Total }}\r\n",
|
||||
"TGUser": "👤 Telegram User: {{ .TelegramID }}\r\n",
|
||||
"exhaustedCount": "🚨 Exhausted {{ .Type }} count:\r\n",
|
||||
"onlinesCount": "🌐 Online Clients: {{ .Count }}\r\n",
|
||||
"disabled": "🛑 Disabled: {{ .Disabled }}\r\n",
|
||||
"depleteSoon": "🔜 Deplete Soon: {{ .Deplete }}\r\n\r\n",
|
||||
"backupTime": "🗄 Backup Time: {{ .Time }}\r\n",
|
||||
"refreshedOn": "\r\n📋🔄 Refreshed On: {{ .Time }}\r\n\r\n",
|
||||
"yes": "✅ Yes",
|
||||
"no": "❌ No",
|
||||
"received_email": "📧📥 Email updated.",
|
||||
"received_comment": "💬📥 Comment updated.",
|
||||
"email_prompt": "📧 Default Email: {{ .ClientEmail }}\n\nEnter your email.",
|
||||
"comment_prompt": "💬 Default Comment: {{ .ClientComment }}\n\nEnter your comment.",
|
||||
"cancel": "❌ Process Canceled! \n\nYou can /start again anytime. 🔄",
|
||||
"error_add_client": "⚠️ Error:\n\n {{ .error }}",
|
||||
"using_default_value": "Okay, I'll stick with the default value. 😊",
|
||||
"incorrect_input": "Your input is not valid.\nThe phrases should be continuous without spaces.\nCorrect example: aaaaaa\nIncorrect example: aaa aaa 🚫",
|
||||
"AreYouSure": "Are you sure? 🤔",
|
||||
"SuccessResetTraffic": "📧 Email: {{ .ClientEmail }}\n🏁 Result: ✅ Success",
|
||||
"FailedResetTraffic": "📧 Email: {{ .ClientEmail }}\n🏁 Result: ❌ Failed \n\n🛠️ Error: [ {{ .ErrorMessage }} ]",
|
||||
"FinishProcess": "🔚 Traffic reset process finished for all clients.",
|
||||
"eventOutboundDown": "Outbound {{ .Tag }} is DOWN",
|
||||
"eventOutboundUp": "Outbound {{ .Tag }} is UP",
|
||||
"eventErrorDetail": "Error: {{ .Error }}",
|
||||
"eventDelayDetail": "Delay: {{ .Delay }}ms",
|
||||
"eventXrayCrash": "Xray CRASHED",
|
||||
"eventXrayCrashError": "Error: {{ .Error }}",
|
||||
"eventNodeDown": "Node {{ .Name }} is DOWN",
|
||||
"eventNodeUp": "Node {{ .Name }} is UP",
|
||||
"eventLoginFallback": "Login failed from {{ .Source }}",
|
||||
"memoryThreshold": "Memory Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%"
|
||||
},
|
||||
"buttons": {
|
||||
"closeKeyboard": "❌ Close Keyboard",
|
||||
"cancel": "❌ Cancel",
|
||||
"cancelReset": "❌ Cancel Reset",
|
||||
"cancelIpLimit": "❌ Cancel IP Limit",
|
||||
"confirmResetTraffic": "✅ Confirm Reset Traffic?",
|
||||
"confirmClearIps": "✅ Confirm Clear IPs?",
|
||||
"confirmRemoveTGUser": "✅ Confirm Remove Telegram User?",
|
||||
"confirmToggle": "✅ Confirm Enable/Disable User?",
|
||||
"dbBackup": "Get DB Backup",
|
||||
"serverUsage": "Server Usage",
|
||||
"getInbounds": "Get Inbounds",
|
||||
"depleteSoon": "Deplete Soon",
|
||||
"clientUsage": "Get Usage",
|
||||
"onlines": "Online Clients",
|
||||
"commands": "Commands",
|
||||
"refresh": "🔄 Refresh",
|
||||
"clearIPs": "❌ Clear IPs",
|
||||
"removeTGUser": "❌ Remove Telegram User",
|
||||
"selectTGUser": "👤 Select Telegram User",
|
||||
"selectOneTGUser": "👤 Select a Telegram User:",
|
||||
"resetTraffic": "📈 Reset Traffic",
|
||||
"resetExpire": "📅 Change Expiry Date",
|
||||
"ipLog": "🔢 IP Log",
|
||||
"ipLimit": "🔢 IP Limit",
|
||||
"setTGUser": "👤 Set Telegram User",
|
||||
"toggle": "🔘 Enable / Disable",
|
||||
"custom": "🔢 Custom",
|
||||
"confirmNumber": "✅ Confirm: {{ .Num }}",
|
||||
"confirmNumberAdd": "✅ Confirm adding: {{ .Num }}",
|
||||
"limitTraffic": "🚧 Traffic Limit",
|
||||
"getBanLogs": "Get Ban Logs",
|
||||
"allClients": "All Clients",
|
||||
"addClient": "Add Client",
|
||||
"submitDisable": "Submit As Disable ☑️",
|
||||
"submitEnable": "Submit As Enable ✅",
|
||||
"use_default": "🏷️ Use default",
|
||||
"change_email": "⚙️📧 Email",
|
||||
"change_comment": "⚙️💬 Comment",
|
||||
"ResetAllTraffics": "Reset All Traffic",
|
||||
"SortedTrafficUsageReport": "Sorted Traffic Usage Report"
|
||||
},
|
||||
"answers": {
|
||||
"successfulOperation": "✅ Operation successful!",
|
||||
"errorOperation": "❗ Error in operation.",
|
||||
"getInboundsFailed": "❌ Failed to get inbounds.",
|
||||
"getClientsFailed": "❌ Failed to get clients.",
|
||||
"canceled": "❌ {{ .Email }}: Operation canceled.",
|
||||
"clientRefreshSuccess": "✅ {{ .Email }}: Client refreshed successfully.",
|
||||
"IpRefreshSuccess": "✅ {{ .Email }}: IPs refreshed successfully.",
|
||||
"TGIdRefreshSuccess": "✅ {{ .Email }}: Client's Telegram User refreshed successfully.",
|
||||
"resetTrafficSuccess": "✅ {{ .Email }}: Traffic reset successfully.",
|
||||
"setTrafficLimitSuccess": "✅ {{ .Email }}: Traffic limit saved successfully.",
|
||||
"expireResetSuccess": "✅ {{ .Email }}: Expire days reset successfully.",
|
||||
"resetIpSuccess": "✅ {{ .Email }}: IP limit {{ .Count }} saved successfully.",
|
||||
"clearIpSuccess": "✅ {{ .Email }}: IPs cleared successfully.",
|
||||
"getIpLog": "✅ {{ .Email }}: Get IP Log.",
|
||||
"getUserInfo": "✅ {{ .Email }}: Get Telegram User Info.",
|
||||
"removedTGUserSuccess": "✅ {{ .Email }}: Telegram User removed successfully.",
|
||||
"enableSuccess": "✅ {{ .Email }}: Enabled successfully.",
|
||||
"disableSuccess": "✅ {{ .Email }}: Disabled successfully.",
|
||||
"askToAddUserId": "Your configuration is not found!\r\nPlease ask your admin to use your Telegram ChatID in your configuration(s).\r\n\r\nYour ChatID: <code>{{ .TgUserID }}</code>",
|
||||
"chooseClient": "Choose a Client for Inbound {{ .Inbound }}",
|
||||
"chooseInbound": "Choose an Inbound"
|
||||
}
|
||||
},
|
||||
"email": {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user