mirror of
				https://github.com/MHSanaei/3x-ui.git
				synced 2025-10-27 02:24:40 +00:00 
			
		
		
		
	[tgbot] Ability to select telegram user for client from bot
This commit is contained in:
		
							parent
							
								
									fbb2ec1e39
								
							
						
					
					
						commit
						58fda2f1ee
					
				
					 2 changed files with 153 additions and 3 deletions
				
			
		|  | @ -673,6 +673,21 @@ func (s *InboundService) DelClientIPs(tx *gorm.DB, email string) error { | ||||||
| 	return tx.Where("client_email = ?", email).Delete(model.InboundClientIps{}).Error | 	return tx.Where("client_email = ?", email).Delete(model.InboundClientIps{}).Error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (s *InboundService) GetClientInboundByTrafficID(trafficId int) (traffic *xray.ClientTraffic, inbound *model.Inbound, err error) { | ||||||
|  | 	db := database.GetDB() | ||||||
|  | 	var traffics []*xray.ClientTraffic | ||||||
|  | 	err = db.Model(xray.ClientTraffic{}).Where("id = ?", trafficId).Find(&traffics).Error | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Warning(err) | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 	if len(traffics) > 0 { | ||||||
|  | 		inbound, err = s.GetInbound(traffics[0].InboundId) | ||||||
|  | 		return traffics[0], inbound, err | ||||||
|  | 	} | ||||||
|  | 	return nil, nil, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (s *InboundService) GetClientInboundByEmail(email string) (traffic *xray.ClientTraffic, inbound *model.Inbound, err error) { | func (s *InboundService) GetClientInboundByEmail(email string) (traffic *xray.ClientTraffic, inbound *model.Inbound, err error) { | ||||||
| 	db := database.GetDB() | 	db := database.GetDB() | ||||||
| 	var traffics []*xray.ClientTraffic | 	var traffics []*xray.ClientTraffic | ||||||
|  | @ -688,6 +703,85 @@ func (s *InboundService) GetClientInboundByEmail(email string) (traffic *xray.Cl | ||||||
| 	return nil, nil, nil | 	return nil, nil, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (s *InboundService) GetClientByEmail(clientEmail string) (*xray.ClientTraffic, *model.Client, error) { | ||||||
|  | 	traffic, inbound, err := s.GetClientInboundByEmail(clientEmail) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 	if inbound == nil { | ||||||
|  | 		return nil, nil, common.NewError("Inbound Not Found For Email:", clientEmail) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	clients, err := s.getClients(inbound) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, client := range clients { | ||||||
|  | 		if client.Email == clientEmail { | ||||||
|  | 			return traffic, &client, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil, nil, common.NewError("Client Not Found In Inbound For Email:", clientEmail) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *InboundService) SetClientTelegramUserID(trafficId int, tgId string) error { | ||||||
|  | 	traffic, inbound, err := s.GetClientInboundByTrafficID(trafficId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if inbound == nil { | ||||||
|  | 		return common.NewError("Inbound Not Found For Traffic ID:", trafficId) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	clientEmail := traffic.Email | ||||||
|  | 
 | ||||||
|  | 	oldClients, err := s.getClients(inbound) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	clientId := "" | ||||||
|  | 
 | ||||||
|  | 	for _, oldClient := range oldClients { | ||||||
|  | 		if oldClient.Email == clientEmail { | ||||||
|  | 			if inbound.Protocol == "trojan" { | ||||||
|  | 				clientId = oldClient.Password | ||||||
|  | 			} else { | ||||||
|  | 				clientId = oldClient.ID | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(clientId) == 0 { | ||||||
|  | 		return common.NewError("Client Not Found For Email:", clientEmail) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var settings map[string]interface{} | ||||||
|  | 	err = json.Unmarshal([]byte(inbound.Settings), &settings) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	clients := settings["clients"].([]interface{}) | ||||||
|  | 	var newClients []interface{} | ||||||
|  | 	for client_index := range clients { | ||||||
|  | 		c := clients[client_index].(map[string]interface{}) | ||||||
|  | 		if c["email"] == clientEmail { | ||||||
|  | 			c["tgId"] = tgId | ||||||
|  | 			newClients = append(newClients, interface{}(c)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	settings["clients"] = newClients | ||||||
|  | 	modifiedSettings, err := json.MarshalIndent(settings, "", "  ") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	inbound.Settings = string(modifiedSettings) | ||||||
|  | 	return s.UpdateInboundClient(inbound, clientId) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, error) { | func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, error) { | ||||||
| 	_, inbound, err := s.GetClientInboundByEmail(clientEmail) | 	_, inbound, err := s.GetClientInboundByEmail(clientEmail) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -101,6 +101,10 @@ func (t *Tgbot) OnReceive() { | ||||||
| 
 | 
 | ||||||
| 	botHandler, _ = th.NewBotHandler(bot, updates) | 	botHandler, _ = th.NewBotHandler(bot, updates) | ||||||
| 
 | 
 | ||||||
|  | 	botHandler.HandleMessage(func(bot *telego.Bot, message telego.Message) { | ||||||
|  | 		t.SendMsgToTgbot(message.Chat.ID, "Custom Keyboard Closed!", tu.ReplyKeyboardRemove()) | ||||||
|  | 	}, th.TextEqual("❌ Close Keyboard")) | ||||||
|  | 
 | ||||||
| 	botHandler.HandleMessage(func(bot *telego.Bot, message telego.Message) { | 	botHandler.HandleMessage(func(bot *telego.Bot, message telego.Message) { | ||||||
| 		t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID)) | 		t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID)) | ||||||
| 	}, th.AnyCommand()) | 	}, th.AnyCommand()) | ||||||
|  | @ -109,6 +113,23 @@ func (t *Tgbot) OnReceive() { | ||||||
| 		t.asnwerCallback(&query, checkAdmin(query.From.ID)) | 		t.asnwerCallback(&query, checkAdmin(query.From.ID)) | ||||||
| 	}, th.AnyCallbackQueryWithMessage()) | 	}, th.AnyCallbackQueryWithMessage()) | ||||||
| 
 | 
 | ||||||
|  | 	botHandler.HandleMessage(func(bot *telego.Bot, message telego.Message) { | ||||||
|  | 		if message.UserShared != nil { | ||||||
|  | 			if checkAdmin(message.From.ID) { | ||||||
|  | 				err := t.inboundService.SetClientTelegramUserID(message.UserShared.RequestID, strconv.FormatInt(message.UserShared.UserID, 10)) | ||||||
|  | 				var output string | ||||||
|  | 				if err != nil { | ||||||
|  | 					output = "❌ Error in user selection!" | ||||||
|  | 				} else { | ||||||
|  | 					output = "✅ Telegram User saved." | ||||||
|  | 				} | ||||||
|  | 				t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove()) | ||||||
|  | 			} else { | ||||||
|  | 				t.SendMsgToTgbot(message.Chat.ID, "No result!", tu.ReplyKeyboardRemove()) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}, th.AnyMessage()) | ||||||
|  | 
 | ||||||
| 	botHandler.Start() | 	botHandler.Start() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -301,6 +322,9 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool | ||||||
| 			case "ip_log": | 			case "ip_log": | ||||||
| 				t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Get IP Log.", email)) | 				t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Get IP Log.", email)) | ||||||
| 				t.searchClientIps(chatId, email) | 				t.searchClientIps(chatId, email) | ||||||
|  | 			case "tg_user": | ||||||
|  | 				t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Get Telegram User Info.", email)) | ||||||
|  | 				t.clientTelegramUserInfo(chatId, email) | ||||||
| 			case "toggle_enable": | 			case "toggle_enable": | ||||||
| 				enabled, err := t.inboundService.ToggleClientEnableByEmail(email) | 				enabled, err := t.inboundService.ToggleClientEnableByEmail(email) | ||||||
| 				if err == nil { | 				if err == nil { | ||||||
|  | @ -386,7 +410,7 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, inlineKeyboard ...*telego.InlineKeyboardMarkup) { | func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, replyMarkup ...telego.ReplyMarkup) { | ||||||
| 	if !isRunning { | 	if !isRunning { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | @ -413,8 +437,8 @@ func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, inlineKeyboard ...*tele | ||||||
| 			Text:      message, | 			Text:      message, | ||||||
| 			ParseMode: "HTML", | 			ParseMode: "HTML", | ||||||
| 		} | 		} | ||||||
| 		if len(inlineKeyboard) > 0 { | 		if len(replyMarkup) > 0 { | ||||||
| 			params.ReplyMarkup = inlineKeyboard[0] | 			params.ReplyMarkup = replyMarkup[0] | ||||||
| 		} | 		} | ||||||
| 		_, err := bot.SendMessage(¶ms) | 		_, err := bot.SendMessage(¶ms) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -613,6 +637,35 @@ func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string) { | ||||||
|  | 	traffic, client, err := t.inboundService.GetClientByEmail(email) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Warning(err) | ||||||
|  | 		msg := "❌ Something went wrong!" | ||||||
|  | 		t.SendMsgToTgbot(chatId, msg) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if client == nil { | ||||||
|  | 		msg := "No result!" | ||||||
|  | 		t.SendMsgToTgbot(chatId, msg) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	output := fmt.Sprintf("📧 Email: %s\r\n👤 Telegram User: %s\r\n", email, client.TgID) | ||||||
|  | 	requestUser := telego.KeyboardButtonRequestUser{ | ||||||
|  | 		RequestID: int32(traffic.Id), | ||||||
|  | 		UserIsBot: false, | ||||||
|  | 	} | ||||||
|  | 	keyboard := tu.Keyboard( | ||||||
|  | 		tu.KeyboardRow( | ||||||
|  | 			tu.KeyboardButton("👤 Select Telegram User").WithRequestUser(&requestUser), | ||||||
|  | 		), | ||||||
|  | 		tu.KeyboardRow( | ||||||
|  | 			tu.KeyboardButton("❌ Close Keyboard"), | ||||||
|  | 		), | ||||||
|  | 	).WithIsPersistent() | ||||||
|  | 	t.SendMsgToTgbot(chatId, output, keyboard) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { | func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { | ||||||
| 	traffic, err := t.inboundService.GetClientTrafficByEmail(email) | 	traffic, err := t.inboundService.GetClientTrafficByEmail(email) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -657,6 +710,9 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { | ||||||
| 			tu.InlineKeyboardButton("🔢 IP Log").WithCallbackData("ip_log "+email), | 			tu.InlineKeyboardButton("🔢 IP Log").WithCallbackData("ip_log "+email), | ||||||
| 			tu.InlineKeyboardButton("🔢 IP Limit").WithCallbackData("ip_limit "+email), | 			tu.InlineKeyboardButton("🔢 IP Limit").WithCallbackData("ip_limit "+email), | ||||||
| 		), | 		), | ||||||
|  | 		tu.InlineKeyboardRow( | ||||||
|  | 			tu.InlineKeyboardButton("👤 Set Telegram User").WithCallbackData("tg_user "+email), | ||||||
|  | 		), | ||||||
| 		tu.InlineKeyboardRow( | 		tu.InlineKeyboardRow( | ||||||
| 			tu.InlineKeyboardButton("🔘 Enable / Disable").WithCallbackData("toggle_enable "+email), | 			tu.InlineKeyboardButton("🔘 Enable / Disable").WithCallbackData("toggle_enable "+email), | ||||||
| 		), | 		), | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Masoud Hidden
						Masoud Hidden