tgbot_router.go 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. package tgbot
  2. import (
  3. "context"
  4. "fmt"
  5. "html"
  6. "slices"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  11. "github.com/mymmrac/telego"
  12. th "github.com/mymmrac/telego/telegohandler"
  13. tu "github.com/mymmrac/telego/telegoutil"
  14. )
  15. // recoverBotPanic must be deferred by every bot handler entry point: telego's
  16. // dispatch has no recovery of its own, so one bad update would kill the panel.
  17. func recoverBotPanic() {
  18. if r := recover(); r != nil {
  19. logger.Error("Recovered panic in Telegram bot handler:", r)
  20. }
  21. }
  22. // runBotHandler runs a bot handler on a worker slot and recovers panics: a bad
  23. // callback must not take down the whole panel, the way a cron panic would not.
  24. func runBotHandler(fn func()) {
  25. messageWorkerPool <- struct{}{}
  26. defer func() { <-messageWorkerPool }()
  27. defer recoverBotPanic()
  28. fn()
  29. }
  30. // chooseInboundClient fetches the inbound once and reuses the row: the inline
  31. // keyboard outlives the inbound, so a stale tap must answer an error, not panic.
  32. func (t *Tgbot) chooseInboundClient(callbackQuery *telego.CallbackQuery, chatId int64, inboundID int, action string) {
  33. inbound, err := t.inboundService.GetInbound(inboundID)
  34. if err != nil {
  35. logger.Warning("chooseInboundClient GetInbound failed:", err)
  36. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getInboundsFailed"))
  37. return
  38. }
  39. clientsKB, err := t.getInboundClientsFor(inbound, action)
  40. if err != nil {
  41. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  42. return
  43. }
  44. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseClient", "Inbound=="+inbound.Remark), clientsKB)
  45. }
  46. // OnReceive starts the message receiving loop for the Telegram bot.
  47. func (t *Tgbot) OnReceive() {
  48. params := telego.GetUpdatesParams{
  49. Timeout: 20, // Reduced timeout to detect connection issues faster
  50. }
  51. // Strict singleton: never start a second long-polling loop.
  52. tgBotMutex.Lock()
  53. if botCancel != nil || isRunning {
  54. tgBotMutex.Unlock()
  55. logger.Warning("TgBot OnReceive called while already running; ignoring.")
  56. return
  57. }
  58. ctx, cancel := context.WithCancel(context.Background())
  59. botCancel = cancel
  60. isRunning = true
  61. // Add to WaitGroup before releasing the lock so StopBot() can't return
  62. // before this receiver goroutine is accounted for.
  63. botWG.Add(1)
  64. tgBotMutex.Unlock()
  65. // Get updates channel using the context with shorter timeout for better error recovery
  66. updates, _ := bot.UpdatesViaLongPolling(ctx, &params)
  67. go func() {
  68. defer botWG.Done()
  69. h, _ := th.NewBotHandler(bot, updates)
  70. tgBotMutex.Lock()
  71. botHandler = h
  72. tgBotMutex.Unlock()
  73. h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
  74. defer recoverBotPanic()
  75. userStateMgr.clear(message.Chat.ID)
  76. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.keyboardClosed"), tu.ReplyKeyboardRemove())
  77. return nil
  78. }, th.TextEqual(t.I18nBot("tgbot.buttons.closeKeyboard")))
  79. h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
  80. defer recoverBotPanic()
  81. if !t.isCommandForCurrentBot(&message) {
  82. return nil
  83. }
  84. // Use goroutine with worker pool for concurrent command processing
  85. go runBotHandler(func() {
  86. userStateMgr.clear(message.Chat.ID)
  87. t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID))
  88. })
  89. return nil
  90. }, th.AnyCommand())
  91. h.HandleCallbackQuery(func(ctx *th.Context, query telego.CallbackQuery) error {
  92. // Use goroutine with worker pool for concurrent callback processing
  93. go runBotHandler(func() {
  94. userStateMgr.clear(query.Message.GetChat().ID)
  95. t.answerCallback(&query, checkAdmin(query.From.ID))
  96. })
  97. return nil
  98. }, th.AnyCallbackQueryWithMessage())
  99. h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
  100. defer recoverBotPanic()
  101. userStateMgr.maybePrune(time.Hour)
  102. if userState, exists := userStateMgr.get(message.Chat.ID); exists {
  103. switch userState {
  104. case "awaiting_email":
  105. if client_Email == strings.TrimSpace(message.Text) {
  106. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  107. userStateMgr.clear(message.Chat.ID)
  108. return nil
  109. }
  110. client_Email = strings.TrimSpace(message.Text)
  111. if t.isSingleWord(client_Email) {
  112. userStateMgr.set(message.Chat.ID, "awaiting_email")
  113. cancel_btn_markup := tu.InlineKeyboard(
  114. tu.InlineKeyboardRow(
  115. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  116. ),
  117. )
  118. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
  119. } else {
  120. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_email"), 3, tu.ReplyKeyboardRemove())
  121. userStateMgr.clear(message.Chat.ID)
  122. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  123. }
  124. case "awaiting_comment":
  125. if client_Comment == strings.TrimSpace(message.Text) {
  126. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  127. userStateMgr.clear(message.Chat.ID)
  128. return nil
  129. }
  130. client_Comment = strings.TrimSpace(message.Text)
  131. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_comment"), 3, tu.ReplyKeyboardRemove())
  132. userStateMgr.clear(message.Chat.ID)
  133. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  134. case "awaiting_tg_id":
  135. input := strings.TrimSpace(message.Text)
  136. if input == "" || input == "-" || strings.EqualFold(input, "none") {
  137. client_TgID = ""
  138. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  139. userStateMgr.clear(message.Chat.ID)
  140. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  141. return nil
  142. }
  143. if _, err := strconv.ParseInt(input, 10, 64); err != nil {
  144. cancel_btn_markup := tu.InlineKeyboard(
  145. tu.InlineKeyboardRow(
  146. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  147. ),
  148. )
  149. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
  150. return nil
  151. }
  152. client_TgID = input
  153. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.userSaved"), 3, tu.ReplyKeyboardRemove())
  154. userStateMgr.clear(message.Chat.ID)
  155. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  156. }
  157. } else {
  158. if message.UsersShared != nil {
  159. if checkAdmin(message.From.ID) {
  160. for _, sharedUser := range message.UsersShared.Users {
  161. userID := sharedUser.UserID
  162. needRestart, err := t.clientService.SetClientTelegramUserID(&t.inboundService, message.UsersShared.RequestID, userID)
  163. if needRestart {
  164. t.xrayService.SetToNeedRestart()
  165. }
  166. output := ""
  167. if err != nil {
  168. output += t.I18nBot("tgbot.messages.selectUserFailed")
  169. } else {
  170. output += t.I18nBot("tgbot.messages.userSaved")
  171. }
  172. t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove())
  173. }
  174. } else {
  175. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.noResult"), tu.ReplyKeyboardRemove())
  176. }
  177. }
  178. }
  179. return nil
  180. }, th.AnyMessage())
  181. _ = h.Start()
  182. }()
  183. }
  184. // answerCommand processes incoming command messages from Telegram users.
  185. func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) {
  186. msg, onlyMessage := "", false
  187. command, _, commandArgs := tu.ParseCommand(message.Text)
  188. // Helper function to handle unknown commands.
  189. handleUnknownCommand := func() {
  190. msg += t.I18nBot("tgbot.commands.unknown")
  191. }
  192. // Handle the command.
  193. switch command {
  194. case "help":
  195. msg += t.I18nBot("tgbot.commands.help")
  196. msg += t.I18nBot("tgbot.commands.pleaseChoose")
  197. case "start":
  198. msg += t.I18nBot("tgbot.commands.start", "Firstname=="+html.EscapeString(message.From.FirstName))
  199. if isAdmin {
  200. msg += t.I18nBot("tgbot.commands.welcome", "Hostname=="+hostname)
  201. }
  202. msg += "\n\n" + t.I18nBot("tgbot.commands.pleaseChoose")
  203. case "status":
  204. onlyMessage = true
  205. msg += t.I18nBot("tgbot.commands.status")
  206. case "id":
  207. onlyMessage = true
  208. msg += t.I18nBot("tgbot.commands.getID", "ID=="+strconv.FormatInt(message.From.ID, 10))
  209. case "usage":
  210. onlyMessage = true
  211. if len(commandArgs) > 0 {
  212. if isAdmin {
  213. t.searchClient(chatId, commandArgs[0])
  214. } else {
  215. t.getClientUsage(chatId, message.From.ID, commandArgs[0])
  216. }
  217. } else {
  218. msg += t.I18nBot("tgbot.commands.usage")
  219. }
  220. case "inbound":
  221. onlyMessage = true
  222. if isAdmin && len(commandArgs) > 0 {
  223. t.searchInbound(chatId, commandArgs[0])
  224. } else {
  225. handleUnknownCommand()
  226. }
  227. case "restart":
  228. onlyMessage = true
  229. if isAdmin {
  230. if len(commandArgs) == 0 {
  231. if t.xrayService.IsXrayRunning() {
  232. err := t.xrayService.RestartXray(true)
  233. if err != nil {
  234. msg += t.I18nBot("tgbot.commands.restartFailed", "Error=="+err.Error())
  235. } else {
  236. msg += t.I18nBot("tgbot.commands.restartSuccess")
  237. }
  238. } else {
  239. msg += t.I18nBot("tgbot.commands.xrayNotRunning")
  240. }
  241. } else {
  242. handleUnknownCommand()
  243. msg += t.I18nBot("tgbot.commands.restartUsage")
  244. }
  245. } else {
  246. handleUnknownCommand()
  247. }
  248. case "clearall":
  249. onlyMessage = true
  250. if isAdmin {
  251. inlineKeyboard := tu.InlineKeyboard(
  252. tu.InlineKeyboardRow(
  253. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("reset_all_traffics_cancel")),
  254. ),
  255. tu.InlineKeyboardRow(
  256. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmResetTraffic")).WithCallbackData(t.encodeQuery("reset_all_traffics_c")),
  257. ),
  258. )
  259. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.AreYouSure"), inlineKeyboard)
  260. } else {
  261. handleUnknownCommand()
  262. }
  263. default:
  264. handleUnknownCommand()
  265. }
  266. if msg != "" {
  267. t.sendResponse(chatId, msg, onlyMessage, isAdmin)
  268. }
  269. }
  270. func (t *Tgbot) isCommandForCurrentBot(message *telego.Message) bool {
  271. return isCommandForBot(message.Text, botUsername())
  272. }
  273. func botUsername() string {
  274. if bot == nil {
  275. return ""
  276. }
  277. return bot.Username()
  278. }
  279. func isCommandForBot(text string, username string) bool {
  280. _, commandUsername, _ := tu.ParseCommand(text)
  281. return commandUsername == "" || username == "" || strings.EqualFold(commandUsername, username)
  282. }
  283. // answerCallback processes callback queries from inline keyboards.
  284. func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) {
  285. chatId := callbackQuery.Message.GetChat().ID
  286. if isAdmin {
  287. // get query from hash storage
  288. decodedQuery, err := t.decodeQuery(callbackQuery.Data)
  289. if err != nil {
  290. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.noQuery"))
  291. return
  292. }
  293. dataArray := strings.Split(decodedQuery, " ")
  294. if len(dataArray) >= 2 && len(dataArray[1]) > 0 {
  295. email := dataArray[1]
  296. switch dataArray[0] {
  297. case "get_clients_for_sub":
  298. inboundIdInt, err := strconv.Atoi(dataArray[1])
  299. if err != nil {
  300. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  301. return
  302. }
  303. t.chooseInboundClient(callbackQuery, chatId, inboundIdInt, "client_sub_links")
  304. case "get_clients_for_individual":
  305. inboundIdInt, err := strconv.Atoi(dataArray[1])
  306. if err != nil {
  307. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  308. return
  309. }
  310. t.chooseInboundClient(callbackQuery, chatId, inboundIdInt, "client_individual_links")
  311. case "get_clients_for_qr":
  312. inboundIdInt, err := strconv.Atoi(dataArray[1])
  313. if err != nil {
  314. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  315. return
  316. }
  317. t.chooseInboundClient(callbackQuery, chatId, inboundIdInt, "client_qr_links")
  318. case "client_sub_links":
  319. t.sendClientSubLinks(chatId, email)
  320. return
  321. case "client_individual_links":
  322. t.sendClientIndividualLinks(chatId, email)
  323. return
  324. case "client_qr_links":
  325. t.sendClientQRLinks(chatId, email)
  326. return
  327. case "client_get_usage":
  328. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.messages.email", "Email=="+email))
  329. t.searchClient(chatId, email)
  330. case "client_refresh":
  331. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.clientRefreshSuccess", "Email=="+email))
  332. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  333. case "client_cancel":
  334. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+email))
  335. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  336. case "ips_refresh":
  337. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.IpRefreshSuccess", "Email=="+email))
  338. t.searchClientIps(chatId, email, callbackQuery.Message.GetMessageID())
  339. case "ips_cancel":
  340. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+email))
  341. t.searchClientIps(chatId, email, callbackQuery.Message.GetMessageID())
  342. case "tgid_refresh":
  343. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.TGIdRefreshSuccess", "Email=="+email))
  344. t.clientTelegramUserInfo(chatId, email, callbackQuery.Message.GetMessageID())
  345. case "tgid_cancel":
  346. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+email))
  347. t.clientTelegramUserInfo(chatId, email, callbackQuery.Message.GetMessageID())
  348. case "reset_traffic":
  349. inlineKeyboard := tu.InlineKeyboard(
  350. tu.InlineKeyboardRow(
  351. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  352. ),
  353. tu.InlineKeyboardRow(
  354. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmResetTraffic")).WithCallbackData(t.encodeQuery("reset_traffic_c "+email)),
  355. ),
  356. )
  357. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  358. case "reset_traffic_c":
  359. err := t.inboundService.ResetClientTrafficByEmail(email)
  360. if err == nil {
  361. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.resetTrafficSuccess", "Email=="+email))
  362. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  363. } else {
  364. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  365. }
  366. case "limit_traffic":
  367. inlineKeyboard := tu.InlineKeyboard(
  368. tu.InlineKeyboardRow(
  369. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  370. ),
  371. tu.InlineKeyboardRow(
  372. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 0")),
  373. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("limit_traffic_in "+email+" 0")),
  374. ),
  375. tu.InlineKeyboardRow(
  376. tu.InlineKeyboardButton("1 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 1")),
  377. tu.InlineKeyboardButton("5 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 5")),
  378. tu.InlineKeyboardButton("10 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 10")),
  379. ),
  380. tu.InlineKeyboardRow(
  381. tu.InlineKeyboardButton("20 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 20")),
  382. tu.InlineKeyboardButton("30 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 30")),
  383. tu.InlineKeyboardButton("40 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 40")),
  384. ),
  385. tu.InlineKeyboardRow(
  386. tu.InlineKeyboardButton("50 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 50")),
  387. tu.InlineKeyboardButton("60 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 60")),
  388. tu.InlineKeyboardButton("80 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 80")),
  389. ),
  390. tu.InlineKeyboardRow(
  391. tu.InlineKeyboardButton("100 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 100")),
  392. tu.InlineKeyboardButton("150 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 150")),
  393. tu.InlineKeyboardButton("200 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 200")),
  394. ),
  395. )
  396. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  397. case "limit_traffic_c":
  398. if len(dataArray) == 3 {
  399. limitTraffic, err := strconv.Atoi(dataArray[2])
  400. if err == nil {
  401. needRestart, err := t.clientService.ResetClientTrafficLimitByEmail(&t.inboundService, email, limitTraffic)
  402. if needRestart {
  403. t.xrayService.SetToNeedRestart()
  404. }
  405. if err == nil {
  406. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.setTrafficLimitSuccess", "Email=="+email))
  407. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  408. return
  409. }
  410. }
  411. }
  412. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  413. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  414. case "limit_traffic_in":
  415. if len(dataArray) >= 3 {
  416. oldInputNumber, err := strconv.Atoi(dataArray[2])
  417. inputNumber := oldInputNumber
  418. if err == nil {
  419. if len(dataArray) == 4 {
  420. num, err := strconv.Atoi(dataArray[3])
  421. if err == nil {
  422. inputNumber = updateNumericInput(inputNumber, num)
  423. }
  424. if inputNumber == oldInputNumber {
  425. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  426. return
  427. }
  428. if inputNumber >= 999999 {
  429. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  430. return
  431. }
  432. }
  433. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "limit_traffic", dataArgs: email + " ", cancelData: "client_cancel " + email, confirmLabelKey: "tgbot.buttons.confirmNumberAdd"}, inputNumber)
  434. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  435. return
  436. }
  437. }
  438. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  439. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  440. case "add_client_limit_traffic_c":
  441. limitTraffic, _ := strconv.ParseInt(dataArray[1], 10, 64)
  442. client_TotalGB = limitTraffic * 1024 * 1024 * 1024
  443. messageId := callbackQuery.Message.GetMessageID()
  444. message_text := t.BuildClientDraftMessage()
  445. t.addClient(callbackQuery.Message.GetChat().ID, message_text, messageId)
  446. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  447. case "add_client_limit_traffic_in":
  448. if len(dataArray) >= 2 {
  449. oldInputNumber, err := strconv.Atoi(dataArray[1])
  450. inputNumber := oldInputNumber
  451. if err == nil {
  452. if len(dataArray) == 3 {
  453. num, err := strconv.Atoi(dataArray[2])
  454. if err == nil {
  455. inputNumber = updateNumericInput(inputNumber, num)
  456. }
  457. if inputNumber == oldInputNumber {
  458. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  459. return
  460. }
  461. if inputNumber >= 999999 {
  462. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  463. return
  464. }
  465. }
  466. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "add_client_limit_traffic", cancelData: "add_client_default_traffic_exp", confirmLabelKey: "tgbot.buttons.confirmNumberAdd"}, inputNumber)
  467. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  468. return
  469. }
  470. }
  471. case "reset_exp":
  472. inlineKeyboard := tu.InlineKeyboard(
  473. tu.InlineKeyboardRow(
  474. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  475. ),
  476. tu.InlineKeyboardRow(
  477. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 0")),
  478. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("reset_exp_in "+email+" 0")),
  479. ),
  480. tu.InlineKeyboardRow(
  481. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 7 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 7")),
  482. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 10 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 10")),
  483. ),
  484. tu.InlineKeyboardRow(
  485. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 14 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 14")),
  486. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 20 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 20")),
  487. ),
  488. tu.InlineKeyboardRow(
  489. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 1 "+t.I18nBot("tgbot.month")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 30")),
  490. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 3 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 90")),
  491. ),
  492. tu.InlineKeyboardRow(
  493. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 6 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 180")),
  494. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 12 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 365")),
  495. ),
  496. )
  497. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  498. case "reset_exp_c":
  499. if len(dataArray) == 3 {
  500. days, err := strconv.ParseInt(dataArray[2], 10, 64)
  501. if err == nil {
  502. var date int64
  503. if days > 0 {
  504. traffic, err := t.inboundService.GetClientTrafficByEmail(email)
  505. if err != nil {
  506. logger.Warning(err)
  507. msg := t.I18nBot("tgbot.wentWrong")
  508. t.SendMsgToTgbot(chatId, msg)
  509. return
  510. }
  511. if traffic == nil {
  512. msg := t.I18nBot("tgbot.noResult")
  513. t.SendMsgToTgbot(chatId, msg)
  514. return
  515. }
  516. if traffic.ExpiryTime > 0 {
  517. if traffic.ExpiryTime-time.Now().Unix()*1000 < 0 {
  518. date = -(days * 24 * 60 * 60000)
  519. } else {
  520. date = traffic.ExpiryTime + days*24*60*60000
  521. }
  522. } else {
  523. date = traffic.ExpiryTime - days*24*60*60000
  524. }
  525. }
  526. needRestart, err := t.clientService.ResetClientExpiryTimeByEmail(&t.inboundService, email, date)
  527. if needRestart {
  528. t.xrayService.SetToNeedRestart()
  529. }
  530. if err == nil {
  531. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.expireResetSuccess", "Email=="+email))
  532. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  533. return
  534. }
  535. }
  536. }
  537. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  538. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  539. case "reset_exp_in":
  540. if len(dataArray) >= 3 {
  541. oldInputNumber, err := strconv.Atoi(dataArray[2])
  542. inputNumber := oldInputNumber
  543. if err == nil {
  544. if len(dataArray) == 4 {
  545. num, err := strconv.Atoi(dataArray[3])
  546. if err == nil {
  547. inputNumber = updateNumericInput(inputNumber, num)
  548. }
  549. if inputNumber == oldInputNumber {
  550. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  551. return
  552. }
  553. if inputNumber >= 999999 {
  554. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  555. return
  556. }
  557. }
  558. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "reset_exp", dataArgs: email + " ", cancelData: "client_cancel " + email, confirmLabelKey: "tgbot.buttons.confirmNumber"}, inputNumber)
  559. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  560. return
  561. }
  562. }
  563. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  564. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  565. case "add_client_reset_exp_c":
  566. client_ExpiryTime = 0
  567. days, _ := strconv.ParseInt(dataArray[1], 10, 64)
  568. var date int64
  569. if client_ExpiryTime > 0 {
  570. if client_ExpiryTime-time.Now().Unix()*1000 < 0 {
  571. date = -(days * 24 * 60 * 60000)
  572. } else {
  573. date = client_ExpiryTime + days*24*60*60000
  574. }
  575. } else {
  576. date = client_ExpiryTime - days*24*60*60000
  577. }
  578. client_ExpiryTime = date
  579. messageId := callbackQuery.Message.GetMessageID()
  580. message_text := t.BuildClientDraftMessage()
  581. t.addClient(callbackQuery.Message.GetChat().ID, message_text, messageId)
  582. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  583. case "add_client_reset_exp_in":
  584. if len(dataArray) >= 2 {
  585. oldInputNumber, err := strconv.Atoi(dataArray[1])
  586. inputNumber := oldInputNumber
  587. if err == nil {
  588. if len(dataArray) == 3 {
  589. num, err := strconv.Atoi(dataArray[2])
  590. if err == nil {
  591. inputNumber = updateNumericInput(inputNumber, num)
  592. }
  593. if inputNumber == oldInputNumber {
  594. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  595. return
  596. }
  597. if inputNumber >= 999999 {
  598. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  599. return
  600. }
  601. }
  602. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "add_client_reset_exp", cancelData: "add_client_default_traffic_exp", confirmLabelKey: "tgbot.buttons.confirmNumberAdd"}, inputNumber)
  603. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  604. return
  605. }
  606. }
  607. case "ip_limit":
  608. inlineKeyboard := tu.InlineKeyboard(
  609. tu.InlineKeyboardRow(
  610. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelIpLimit")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  611. ),
  612. tu.InlineKeyboardRow(
  613. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 0")),
  614. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("ip_limit_in "+email+" 0")),
  615. ),
  616. tu.InlineKeyboardRow(
  617. tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 1")),
  618. tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 2")),
  619. ),
  620. tu.InlineKeyboardRow(
  621. tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 3")),
  622. tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 4")),
  623. ),
  624. tu.InlineKeyboardRow(
  625. tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 5")),
  626. tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 6")),
  627. tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 7")),
  628. ),
  629. tu.InlineKeyboardRow(
  630. tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 8")),
  631. tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 9")),
  632. tu.InlineKeyboardButton("10").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 10")),
  633. ),
  634. )
  635. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  636. case "ip_limit_c":
  637. if len(dataArray) == 3 {
  638. count, err := strconv.Atoi(dataArray[2])
  639. if err == nil {
  640. needRestart, err := t.clientService.ResetClientIpLimitByEmail(&t.inboundService, email, count)
  641. if needRestart {
  642. t.xrayService.SetToNeedRestart()
  643. }
  644. if err == nil {
  645. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.resetIpSuccess", "Email=="+email, "Count=="+strconv.Itoa(count)))
  646. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  647. return
  648. }
  649. }
  650. }
  651. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  652. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  653. case "ip_limit_in":
  654. if len(dataArray) >= 3 {
  655. oldInputNumber, err := strconv.Atoi(dataArray[2])
  656. inputNumber := oldInputNumber
  657. if err == nil {
  658. if len(dataArray) == 4 {
  659. num, err := strconv.Atoi(dataArray[3])
  660. if err == nil {
  661. inputNumber = updateNumericInput(inputNumber, num)
  662. }
  663. if inputNumber == oldInputNumber {
  664. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  665. return
  666. }
  667. if inputNumber >= 999999 {
  668. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  669. return
  670. }
  671. }
  672. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "ip_limit", dataArgs: email + " ", cancelData: "client_cancel " + email, confirmLabelKey: "tgbot.buttons.confirmNumber"}, inputNumber)
  673. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  674. return
  675. }
  676. }
  677. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  678. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  679. case "add_client_ip_limit_c":
  680. if len(dataArray) == 2 {
  681. count, _ := strconv.Atoi(dataArray[1])
  682. client_LimitIP = count
  683. }
  684. messageId := callbackQuery.Message.GetMessageID()
  685. message_text := t.BuildClientDraftMessage()
  686. t.addClient(callbackQuery.Message.GetChat().ID, message_text, messageId)
  687. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  688. case "add_client_ip_limit_in":
  689. if len(dataArray) >= 2 {
  690. oldInputNumber, err := strconv.Atoi(dataArray[1])
  691. inputNumber := oldInputNumber
  692. if err == nil {
  693. if len(dataArray) == 3 {
  694. num, err := strconv.Atoi(dataArray[2])
  695. if err == nil {
  696. inputNumber = updateNumericInput(inputNumber, num)
  697. }
  698. if inputNumber == oldInputNumber {
  699. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  700. return
  701. }
  702. if inputNumber >= 999999 {
  703. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  704. return
  705. }
  706. }
  707. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "add_client_ip_limit", cancelData: "add_client_default_ip_limit", confirmLabelKey: "tgbot.buttons.confirmNumber"}, inputNumber)
  708. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  709. return
  710. }
  711. }
  712. case "clear_ips":
  713. inlineKeyboard := tu.InlineKeyboard(
  714. tu.InlineKeyboardRow(
  715. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("ips_cancel "+email)),
  716. ),
  717. tu.InlineKeyboardRow(
  718. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmClearIps")).WithCallbackData(t.encodeQuery("clear_ips_c "+email)),
  719. ),
  720. )
  721. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  722. case "clear_ips_c":
  723. err := t.inboundService.ClearClientIps(email)
  724. if err == nil {
  725. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.clearIpSuccess", "Email=="+email))
  726. t.searchClientIps(chatId, email, callbackQuery.Message.GetMessageID())
  727. } else {
  728. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  729. }
  730. case "ip_log":
  731. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getIpLog", "Email=="+email))
  732. t.searchClientIps(chatId, email)
  733. case "tg_user":
  734. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getUserInfo", "Email=="+email))
  735. t.clientTelegramUserInfo(chatId, email)
  736. case "tgid_remove":
  737. inlineKeyboard := tu.InlineKeyboard(
  738. tu.InlineKeyboardRow(
  739. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("tgid_cancel "+email)),
  740. ),
  741. tu.InlineKeyboardRow(
  742. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmRemoveTGUser")).WithCallbackData(t.encodeQuery("tgid_remove_c "+email)),
  743. ),
  744. )
  745. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  746. case "tgid_remove_c":
  747. traffic, err := t.inboundService.GetClientTrafficByEmail(email)
  748. if err != nil || traffic == nil {
  749. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  750. return
  751. }
  752. needRestart, err := t.clientService.SetClientTelegramUserID(&t.inboundService, traffic.Id, EmptyTelegramUserID)
  753. if needRestart {
  754. t.xrayService.SetToNeedRestart()
  755. }
  756. if err == nil {
  757. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.removedTGUserSuccess", "Email=="+email))
  758. t.clientTelegramUserInfo(chatId, email, callbackQuery.Message.GetMessageID())
  759. } else {
  760. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  761. }
  762. case "toggle_enable":
  763. inlineKeyboard := tu.InlineKeyboard(
  764. tu.InlineKeyboardRow(
  765. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  766. ),
  767. tu.InlineKeyboardRow(
  768. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmToggle")).WithCallbackData(t.encodeQuery("toggle_enable_c "+email)),
  769. ),
  770. )
  771. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  772. case "toggle_enable_c":
  773. enabled, needRestart, err := t.clientService.ToggleClientEnableByEmail(&t.inboundService, email)
  774. if needRestart {
  775. t.xrayService.SetToNeedRestart()
  776. }
  777. if err == nil {
  778. if enabled {
  779. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.enableSuccess", "Email=="+email))
  780. } else {
  781. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.disableSuccess", "Email=="+email))
  782. }
  783. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  784. } else {
  785. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  786. }
  787. case "get_clients":
  788. inboundId := dataArray[1]
  789. inboundIdInt, err := strconv.Atoi(inboundId)
  790. if err != nil {
  791. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  792. return
  793. }
  794. inbound, err := t.inboundService.GetInbound(inboundIdInt)
  795. if err != nil {
  796. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  797. return
  798. }
  799. clients, err := t.getInboundClients(inboundIdInt)
  800. if err != nil {
  801. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  802. return
  803. }
  804. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseClient", "Inbound=="+inbound.Remark), clients)
  805. case "add_client_to":
  806. client_Email = t.randomLowerAndNum(8)
  807. client_LimitIP = 0
  808. client_TotalGB = 0
  809. client_ExpiryTime = 0
  810. client_Enable = true
  811. client_TgID = ""
  812. client_SubID = t.randomLowerAndNum(16)
  813. client_Comment = ""
  814. client_Reset = 0
  815. inboundId := dataArray[1]
  816. inboundIdInt, err := strconv.Atoi(inboundId)
  817. if err != nil {
  818. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  819. return
  820. }
  821. receiver_inbound_ID = inboundIdInt
  822. receiver_inbound_IDs = []int{inboundIdInt}
  823. t.addClient(callbackQuery.Message.GetChat().ID, t.BuildClientDraftMessage())
  824. case "add_client_toggle_attach":
  825. inboundIdStr := dataArray[1]
  826. inboundIdInt, err := strconv.Atoi(inboundIdStr)
  827. if err != nil {
  828. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  829. return
  830. }
  831. found := -1
  832. for i, id := range receiver_inbound_IDs {
  833. if id == inboundIdInt {
  834. found = i
  835. break
  836. }
  837. }
  838. if found >= 0 {
  839. receiver_inbound_IDs = append(receiver_inbound_IDs[:found], receiver_inbound_IDs[found+1:]...)
  840. } else {
  841. receiver_inbound_IDs = append(receiver_inbound_IDs, inboundIdInt)
  842. }
  843. picker, err := t.getInboundsAttachPicker()
  844. if err != nil {
  845. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  846. return
  847. }
  848. t.editMessageCallbackTgBot(callbackQuery.Message.GetChat().ID, callbackQuery.Message.GetMessageID(), picker)
  849. }
  850. return
  851. } else {
  852. switch callbackQuery.Data {
  853. case "get_inbounds":
  854. inbounds, err := t.getInbounds()
  855. if err != nil {
  856. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  857. return
  858. }
  859. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.allClients"))
  860. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  861. case "admin_client_sub_links":
  862. inbounds, err := t.getInboundsFor("get_clients_for_sub")
  863. if err != nil {
  864. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  865. return
  866. }
  867. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  868. case "admin_client_individual_links":
  869. inbounds, err := t.getInboundsFor("get_clients_for_individual")
  870. if err != nil {
  871. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  872. return
  873. }
  874. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  875. case "admin_client_qr_links":
  876. inbounds, err := t.getInboundsFor("get_clients_for_qr")
  877. if err != nil {
  878. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  879. return
  880. }
  881. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  882. }
  883. }
  884. }
  885. if !isAdmin {
  886. // encodeQuery hashes any payload past 64 chars, so a long email's button
  887. // must be decoded before the gate can see which client it names.
  888. if decoded, err := t.decodeQuery(callbackQuery.Data); err == nil {
  889. callbackQuery.Data = decoded
  890. }
  891. if !isClientSelfCallback(callbackQuery.Data) {
  892. return
  893. }
  894. }
  895. switch callbackQuery.Data {
  896. case "get_usage":
  897. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.serverUsage"))
  898. t.getServerUsage(chatId)
  899. case "usage_refresh":
  900. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  901. t.getServerUsage(chatId, callbackQuery.Message.GetMessageID())
  902. case "inbounds":
  903. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.getInbounds"))
  904. t.SendMsgToTgbot(chatId, t.getInboundUsages())
  905. case "deplete_soon":
  906. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.depleteSoon"))
  907. t.getExhausted(chatId)
  908. case "get_backup":
  909. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.dbBackup"))
  910. t.sendBackup(chatId)
  911. case "get_banlogs":
  912. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.getBanLogs"))
  913. t.sendBanLogs(chatId, true)
  914. case "client_traffic":
  915. tgUserID := callbackQuery.From.ID
  916. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.clientUsage"))
  917. t.getClientUsage(chatId, tgUserID)
  918. case "client_commands":
  919. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.commands"))
  920. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.helpClientCommands"))
  921. case "client_sub_links":
  922. // show user's own clients to choose one for sub links
  923. tgUserID := callbackQuery.From.ID
  924. traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
  925. if err != nil {
  926. // fallback to message
  927. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
  928. return
  929. }
  930. if len(traffics) == 0 {
  931. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+strconv.FormatInt(tgUserID, 10)))
  932. return
  933. }
  934. var buttons []telego.InlineKeyboardButton
  935. for _, tr := range traffics {
  936. buttons = append(buttons, tu.InlineKeyboardButton(tr.Email).WithCallbackData(t.encodeQuery("client_sub_links "+tr.Email)))
  937. }
  938. cols := 1
  939. if len(buttons) >= 6 {
  940. cols = 2
  941. }
  942. keyboard := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols, buttons...))
  943. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.pleaseChoose"), keyboard)
  944. case "client_individual_links":
  945. // show user's clients to choose for individual links
  946. tgUserID := callbackQuery.From.ID
  947. traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
  948. if err != nil {
  949. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
  950. return
  951. }
  952. if len(traffics) == 0 {
  953. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+strconv.FormatInt(tgUserID, 10)))
  954. return
  955. }
  956. var buttons2 []telego.InlineKeyboardButton
  957. for _, tr := range traffics {
  958. buttons2 = append(buttons2, tu.InlineKeyboardButton(tr.Email).WithCallbackData(t.encodeQuery("client_individual_links "+tr.Email)))
  959. }
  960. cols2 := 1
  961. if len(buttons2) >= 6 {
  962. cols2 = 2
  963. }
  964. keyboard2 := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols2, buttons2...))
  965. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.pleaseChoose"), keyboard2)
  966. case "client_qr_links":
  967. // show user's clients to choose for QR codes
  968. tgUserID := callbackQuery.From.ID
  969. traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
  970. if err != nil {
  971. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOccurred")+"\r\n"+err.Error())
  972. return
  973. }
  974. if len(traffics) == 0 {
  975. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+strconv.FormatInt(tgUserID, 10)))
  976. return
  977. }
  978. var buttons3 []telego.InlineKeyboardButton
  979. for _, tr := range traffics {
  980. buttons3 = append(buttons3, tu.InlineKeyboardButton(tr.Email).WithCallbackData(t.encodeQuery("client_qr_links "+tr.Email)))
  981. }
  982. cols3 := 1
  983. if len(buttons3) >= 6 {
  984. cols3 = 2
  985. }
  986. keyboard3 := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols3, buttons3...))
  987. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.pleaseChoose"), keyboard3)
  988. case "onlines":
  989. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.onlines"))
  990. t.onlineClients(chatId)
  991. case "onlines_refresh":
  992. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  993. t.onlineClients(chatId, callbackQuery.Message.GetMessageID())
  994. case "commands":
  995. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.commands"))
  996. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.helpAdminCommands"))
  997. case "add_client":
  998. client_Email = t.randomLowerAndNum(8)
  999. client_LimitIP = 0
  1000. client_TotalGB = 0
  1001. client_ExpiryTime = 0
  1002. client_Enable = true
  1003. client_TgID = ""
  1004. client_SubID = t.randomLowerAndNum(16)
  1005. client_Comment = ""
  1006. client_Reset = 0
  1007. inbounds, err := t.getInboundsAddClient()
  1008. if err != nil {
  1009. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  1010. return
  1011. }
  1012. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.addClient"))
  1013. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  1014. case "add_client_ch_default_email":
  1015. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1016. userStateMgr.set(chatId, "awaiting_email")
  1017. cancel_btn_markup := tu.InlineKeyboard(
  1018. tu.InlineKeyboardRow(
  1019. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  1020. ),
  1021. )
  1022. prompt_message := t.I18nBot("tgbot.messages.email_prompt", "ClientEmail=="+client_Email)
  1023. t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
  1024. case "add_client_ch_default_comment":
  1025. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1026. userStateMgr.set(chatId, "awaiting_comment")
  1027. cancel_btn_markup := tu.InlineKeyboard(
  1028. tu.InlineKeyboardRow(
  1029. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  1030. ),
  1031. )
  1032. prompt_message := t.I18nBot("tgbot.messages.comment_prompt", "ClientComment=="+client_Comment)
  1033. t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
  1034. case "add_client_ch_default_tg_id":
  1035. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1036. userStateMgr.set(chatId, "awaiting_tg_id")
  1037. cancel_btn_markup := tu.InlineKeyboard(
  1038. tu.InlineKeyboardRow(
  1039. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  1040. ),
  1041. )
  1042. current := client_TgID
  1043. if current == "" {
  1044. current = "—"
  1045. }
  1046. t.SendMsgToTgbot(chatId, fmt.Sprintf("Send the Telegram user id (numeric) to attach to this client, or send `-` / `none` to clear.\nCurrent: `%s`", current), cancel_btn_markup)
  1047. case "add_client_ch_default_traffic":
  1048. inlineKeyboard := tu.InlineKeyboard(
  1049. tu.InlineKeyboardRow(
  1050. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
  1051. ),
  1052. tu.InlineKeyboardRow(
  1053. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 0")),
  1054. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_in 0")),
  1055. ),
  1056. tu.InlineKeyboardRow(
  1057. tu.InlineKeyboardButton("1 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 1")),
  1058. tu.InlineKeyboardButton("5 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 5")),
  1059. tu.InlineKeyboardButton("10 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 10")),
  1060. ),
  1061. tu.InlineKeyboardRow(
  1062. tu.InlineKeyboardButton("20 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 20")),
  1063. tu.InlineKeyboardButton("30 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 30")),
  1064. tu.InlineKeyboardButton("40 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 40")),
  1065. ),
  1066. tu.InlineKeyboardRow(
  1067. tu.InlineKeyboardButton("50 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 50")),
  1068. tu.InlineKeyboardButton("60 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 60")),
  1069. tu.InlineKeyboardButton("80 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 80")),
  1070. ),
  1071. tu.InlineKeyboardRow(
  1072. tu.InlineKeyboardButton("100 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 100")),
  1073. tu.InlineKeyboardButton("150 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 150")),
  1074. tu.InlineKeyboardButton("200 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 200")),
  1075. ),
  1076. )
  1077. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  1078. case "add_client_ch_default_exp":
  1079. inlineKeyboard := tu.InlineKeyboard(
  1080. tu.InlineKeyboardRow(
  1081. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
  1082. ),
  1083. tu.InlineKeyboardRow(
  1084. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 0")),
  1085. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_reset_exp_in 0")),
  1086. ),
  1087. tu.InlineKeyboardRow(
  1088. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 7 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 7")),
  1089. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 10 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 10")),
  1090. ),
  1091. tu.InlineKeyboardRow(
  1092. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 14 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 14")),
  1093. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 20 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 20")),
  1094. ),
  1095. tu.InlineKeyboardRow(
  1096. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 1 "+t.I18nBot("tgbot.month")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 30")),
  1097. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 3 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 90")),
  1098. ),
  1099. tu.InlineKeyboardRow(
  1100. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 6 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 180")),
  1101. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 12 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 365")),
  1102. ),
  1103. )
  1104. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  1105. case "add_client_ch_default_ip_limit":
  1106. inlineKeyboard := tu.InlineKeyboard(
  1107. tu.InlineKeyboardRow(
  1108. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_ip_limit")),
  1109. ),
  1110. tu.InlineKeyboardRow(
  1111. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_ip_limit_c 0")),
  1112. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_ip_limit_in 0")),
  1113. ),
  1114. tu.InlineKeyboardRow(
  1115. tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 1")),
  1116. tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 2")),
  1117. ),
  1118. tu.InlineKeyboardRow(
  1119. tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 3")),
  1120. tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 4")),
  1121. ),
  1122. tu.InlineKeyboardRow(
  1123. tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 5")),
  1124. tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 6")),
  1125. tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 7")),
  1126. ),
  1127. tu.InlineKeyboardRow(
  1128. tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 8")),
  1129. tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 9")),
  1130. tu.InlineKeyboardButton("10").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 10")),
  1131. ),
  1132. )
  1133. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  1134. case "add_client_default_info":
  1135. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1136. t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  1137. userStateMgr.clear(chatId)
  1138. t.addClient(chatId, t.BuildClientDraftMessage())
  1139. case "add_client_cancel":
  1140. userStateMgr.clear(chatId)
  1141. receiver_inbound_ID = 0
  1142. receiver_inbound_IDs = nil
  1143. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1144. t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.cancel"), 3, tu.ReplyKeyboardRemove())
  1145. case "add_client_default_traffic_exp":
  1146. messageId := callbackQuery.Message.GetMessageID()
  1147. message_text := t.BuildClientDraftMessage()
  1148. t.addClient(chatId, message_text, messageId)
  1149. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+client_Email))
  1150. case "add_client_default_ip_limit":
  1151. messageId := callbackQuery.Message.GetMessageID()
  1152. message_text := t.BuildClientDraftMessage()
  1153. t.addClient(chatId, message_text, messageId)
  1154. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+client_Email))
  1155. case "add_client_attach_more":
  1156. picker, err := t.getInboundsAttachPicker()
  1157. if err != nil {
  1158. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  1159. return
  1160. }
  1161. t.SendMsgToTgbot(chatId, "Pick inbound(s) to attach:", picker)
  1162. case "add_client_attach_done":
  1163. if receiver_inbound_ID == 0 && len(receiver_inbound_IDs) > 0 {
  1164. receiver_inbound_ID = receiver_inbound_IDs[0]
  1165. }
  1166. if receiver_inbound_ID == 0 {
  1167. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getInboundsFailed"))
  1168. return
  1169. }
  1170. message_text := t.BuildClientDraftMessage()
  1171. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1172. t.addClient(chatId, message_text)
  1173. case "add_client_submit_disable":
  1174. client_Enable = false
  1175. _, err := t.SubmitAddClient()
  1176. if err != nil {
  1177. errorMessage := fmt.Sprintf("%v", err)
  1178. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.error_add_client", "error=="+errorMessage), tu.ReplyKeyboardRemove())
  1179. } else {
  1180. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1181. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
  1182. t.sendClientIndividualLinks(chatId, client_Email)
  1183. t.sendClientQRLinks(chatId, client_Email)
  1184. receiver_inbound_ID = 0
  1185. receiver_inbound_IDs = nil
  1186. }
  1187. case "add_client_submit_enable":
  1188. client_Enable = true
  1189. _, err := t.SubmitAddClient()
  1190. if err != nil {
  1191. errorMessage := fmt.Sprintf("%v", err)
  1192. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.error_add_client", "error=="+errorMessage), tu.ReplyKeyboardRemove())
  1193. } else {
  1194. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1195. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
  1196. t.sendClientIndividualLinks(chatId, client_Email)
  1197. t.sendClientQRLinks(chatId, client_Email)
  1198. receiver_inbound_ID = 0
  1199. receiver_inbound_IDs = nil
  1200. }
  1201. case "reset_all_traffics_cancel":
  1202. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1203. t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.cancel"), 1, tu.ReplyKeyboardRemove())
  1204. case "reset_all_traffics":
  1205. inlineKeyboard := tu.InlineKeyboard(
  1206. tu.InlineKeyboardRow(
  1207. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("reset_all_traffics_cancel")),
  1208. ),
  1209. tu.InlineKeyboardRow(
  1210. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmResetTraffic")).WithCallbackData(t.encodeQuery("reset_all_traffics_c")),
  1211. ),
  1212. )
  1213. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.AreYouSure"), inlineKeyboard)
  1214. case "reset_all_traffics_c":
  1215. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1216. emails, err := t.inboundService.GetAllEmails()
  1217. if err != nil {
  1218. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation"), tu.ReplyKeyboardRemove())
  1219. return
  1220. }
  1221. for _, email := range emails {
  1222. err := t.inboundService.ResetClientTrafficByEmail(email)
  1223. if err == nil {
  1224. msg := t.I18nBot("tgbot.messages.SuccessResetTraffic", "ClientEmail=="+email)
  1225. t.SendMsgToTgbot(chatId, msg, tu.ReplyKeyboardRemove())
  1226. } else {
  1227. msg := t.I18nBot("tgbot.messages.FailedResetTraffic", "ClientEmail=="+email, "ErrorMessage=="+err.Error())
  1228. t.SendMsgToTgbot(chatId, msg, tu.ReplyKeyboardRemove())
  1229. }
  1230. }
  1231. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.FinishProcess"), tu.ReplyKeyboardRemove())
  1232. case "get_sorted_traffic_usage_report":
  1233. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1234. emails, err := t.inboundService.GetAllEmails()
  1235. if err != nil {
  1236. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation"), tu.ReplyKeyboardRemove())
  1237. return
  1238. }
  1239. valid_emails, extra_emails, err := t.inboundService.FilterAndSortClientEmails(emails)
  1240. if err != nil {
  1241. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation"), tu.ReplyKeyboardRemove())
  1242. return
  1243. }
  1244. for _, valid_emails := range valid_emails {
  1245. traffic, err := t.inboundService.GetClientTrafficByEmail(valid_emails)
  1246. if err != nil {
  1247. logger.Warning(err)
  1248. msg := t.I18nBot("tgbot.wentWrong")
  1249. t.SendMsgToTgbot(chatId, msg)
  1250. continue
  1251. }
  1252. if traffic == nil {
  1253. msg := t.I18nBot("tgbot.noResult")
  1254. t.SendMsgToTgbot(chatId, msg)
  1255. continue
  1256. }
  1257. output := t.clientInfoMsg(traffic, false, false, false, false, true, false)
  1258. t.SendMsgToTgbot(chatId, output, tu.ReplyKeyboardRemove())
  1259. }
  1260. for _, extra_emails := range extra_emails {
  1261. msg := fmt.Sprintf("📧 %s\n%s", extra_emails, t.I18nBot("tgbot.noResult"))
  1262. t.SendMsgToTgbot(chatId, msg, tu.ReplyKeyboardRemove())
  1263. }
  1264. default:
  1265. action, email, ok := splitClientLinkCallback(callbackQuery.Data)
  1266. if !ok {
  1267. return
  1268. }
  1269. // The keyboard outlives the chat it was sent to, so the email in it
  1270. // cannot authorise itself: a non-admin only reaches their own clients.
  1271. if !isAdmin && !t.clientOwnedByTgUser(callbackQuery.From.ID, email) {
  1272. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  1273. return
  1274. }
  1275. switch action {
  1276. case "client_sub_links":
  1277. t.sendClientSubLinks(chatId, email)
  1278. case "client_individual_links":
  1279. t.sendClientIndividualLinks(chatId, email)
  1280. case "client_qr_links":
  1281. t.sendClientQRLinks(chatId, email)
  1282. }
  1283. }
  1284. }
  1285. // checkAdmin checks if the given Telegram ID is an admin.
  1286. func checkAdmin(tgId int64) bool {
  1287. return slices.Contains(adminSnapshot(), tgId)
  1288. }
  1289. // isClientSelfCallback reports whether a callback is per-user rather than
  1290. // admin-only; the caller still has to prove the client is its own.
  1291. func isClientSelfCallback(data string) bool {
  1292. switch data {
  1293. case "client_traffic", "client_commands", "client_sub_links",
  1294. "client_individual_links", "client_qr_links":
  1295. return true
  1296. }
  1297. _, _, ok := splitClientLinkCallback(data)
  1298. return ok
  1299. }
  1300. // splitClientLinkCallback splits "<action> <email>" for the per-client link
  1301. // callbacks; ok is false for every other data.
  1302. func splitClientLinkCallback(data string) (action, email string, ok bool) {
  1303. for _, candidate := range []string{"client_sub_links", "client_individual_links", "client_qr_links"} {
  1304. if rest, found := strings.CutPrefix(data, candidate+" "); found && rest != "" {
  1305. return candidate, rest, true
  1306. }
  1307. }
  1308. return "", "", false
  1309. }