📜 ⬆️ ⬇️

Registration using telegram bot

Now almost all sites have registration. It is implemented most often with the help of e-mail, less often with the help of SMS. And what if you register via telegram bot? As a login on the site, we will be able to use a verified phone number, and the bot itself will send one-time access codes. This article describes the process of creating such a bot in the Golang language.

image
Bot work example

I would like to immediately note: the article will not describe the implementation of the entrance to the site using one-time codes.

All code is in the repository on GitHub
')
UPD 02/07/2018: Login to the site using Telegram can now be implemented using Telegram Login Widget

Table of contents:


  1. Required software
  2. Getting API key
  3. Project structure
  4. Settings file
  5. Initialize the bot and connect to the database
  6. Main code
  7. Run bot

First you need to install all the necessary software:


Next you should get an API key for our future bot. To do this, write bot bot. What approximately should turn out:

image

Before you start programming, you need to determine the structure of the project, I got it like this:

/project/ /conf/ settings.go /src/ database.go telegramBot.go main.go 

Start writing code! First, the settings file (settings.go):

 const ( TELEGRAM_BOT_API_KEY = "paste your key here" // API ,     BotFather MONGODB_CONNECTION_URL = "localhost" //   MongoDB MONGODB_DATABASE_NAME = "regbot" //    MONGODB_COLLECTION_USERS = "users" //   ) 

For each user in the database are stored: chat ID ( chat_id ) and mobile phone number ( phone_number ). Therefore, we immediately create a User structure:

 type User struct { Chat_ID int64 Phone_Number string } 

We can connect to MongoDB using the DatabaseConnection structure:

 type DatabaseConnection struct { Session *mgo.Session //    DB *mgo.Database //     } 

We will represent the bot as a TelegramBot structure:

 type TelegramBot struct { API *tgbotapi.BotAPI // API  Updates tgbotapi.UpdatesChannel //   ActiveContactRequests []int64 // ID ,      } 

The function to initialize the connection with MongoDB:

 func (connection *DatabaseConnection) Init() { session, err := mgo.Dial(conf.MONGODB_CONNECTION_URL) //    if err != nil { log.Fatal(err) //      } connection.Session = session db := session.DB(conf.MONGODB_DATABASE_NAME) //     connection.DB = db } 

Bot initialization function:

 func (telegramBot *TelegramBot) Init() { botAPI, err := tgbotapi.NewBotAPI(conf.TELEGRAM_BOT_API_KEY) //  API if err != nil { log.Fatal(err) } telegramBot.API = botAPI botUpdate := tgbotapi.NewUpdate(0) //    botUpdate.Timeout = 64 botUpdates, err := telegramBot.API.GetUpdatesChan(botUpdate) if err != nil { log.Fatal(err) } telegramBot.Updates = botUpdates } 

The bot is initialized, but it still can not do anything. Let's move on!

The next step is the “main bot cycle”:

 func (telegramBot *TelegramBot) Start() { for update := range telegramBot.Updates { if update.Message != nil { //    ->   telegramBot.analyzeUpdate(update) } } } 

This is an endless loop. Processing of all incoming messages begins with it. At the beginning of processing, we must check whether we have a user in the database. No - we create and request its number, there is - we continue processing.

 //    func (telegramBot *TelegramBot) analyzeUpdate(update tgbotapi.Update) { chatID := update.Message.Chat.ID if telegramBot.findUser(chatID) { //     ? telegramBot.analyzeUser(update) } else { telegramBot.createUser(User{chatID, ""}) //   telegramBot.requestContact(chatID) //   } } func (telegramBot *TelegramBot) findUser(chatID int64) bool { find, err := Connection.Find(chatID) if err != nil { msg := tgbotapi.NewMessage(chatID, " !    !") telegramBot.API.Send(msg) } return find } func (telegramBot *TelegramBot) createUser(user User) { err := Connection.CreateUser(user) if err != nil { msg := tgbotapi.NewMessage(user.Chat_ID, " !    !") telegramBot.API.Send(msg) } } func (telegramBot *TelegramBot) requestContact(chatID int64) { //   requestContactMessage := tgbotapi.NewMessage(chatID, "          ?") //     acceptButton := tgbotapi.NewKeyboardButtonContact("") declineButton := tgbotapi.NewKeyboardButton("") //   requestContactReplyKeyboard := tgbotapi.NewReplyKeyboard([]tgbotapi.KeyboardButton{acceptButton, declineButton}) requestContactMessage.ReplyMarkup = requestContactReplyKeyboard telegramBot.API.Send(requestContactMessage) //   telegramBot.addContactRequestID(chatID) //  ChatID    } func (telegramBot *TelegramBot) addContactRequestID(chatID int64) { telegramBot.ActiveContactRequests = append(telegramBot.ActiveContactRequests, chatID) } 

The initial processing is written, now let's write a conversation with the database:

 var Connection DatabaseConnection // ,        //     func (connection *DatabaseConnection) Find(chatID int64) (bool, error) { collection := connection.DB.C(conf.MONGODB_COLLECTION_USERS) //   "users" count, err := collection.Find(bson.M{"chat_id": chatID}).Count() //      ChatID if err != nil || count == 0 { return false, err } else { return true, err } } //   func (connection *DatabaseConnection) GetUser(chatID int64) (User, error) { var result User find, err := connection.Find(chatID) //  ,    if err != nil { return result, err } if find { //   ->  collection := connection.DB.C(conf.MONGODB_COLLECTION_USERS) err = collection.Find(bson.M{"chat_id": chatID}).One(&result) return result, err } else { //  ->  NotFound return result, mgo.ErrNotFound } } //   func (connection *DatabaseConnection) CreateUser(user User) error { collection := connection.DB.C(conf.MONGODB_COLLECTION_USERS) err := collection.Insert(user) return err } //     func (connection *DatabaseConnection) UpdateUser(user User) error { collection := connection.DB.C(conf.MONGODB_COLLECTION_USERS) err := collection.Update(bson.M{"chat_id": user.Chat_ID}, &user) return err } 

These are all functions that will be useful to us. For the bot, it remains to write functions to continue processing the message and analyzing the contact:

 func (telegramBot *TelegramBot) analyzeUser(update tgbotapi.Update) { chatID := update.Message.Chat.ID user, err := Connection.GetUser(chatID) //        if err != nil { msg := tgbotapi.NewMessage(chatID, " !    !") telegramBot.API.Send(msg) return } if len(user.Phone_Number) > 0 { msg := tgbotapi.NewMessage(chatID, " : " + user.Phone_Number) //      ,    telegramBot.API.Send(msg) return } else { //   ,         ChatID if telegramBot.findContactRequestID(chatID) { telegramBot.checkRequestContactReply(update) //   ->  return } else { telegramBot.requestContact(chatID) //   ->   return } } } //    func (telegramBot *TelegramBot) checkRequestContactReply(update tgbotapi.Update) { if update.Message.Contact != nil { // ,     if update.Message.Contact.UserID == update.Message.From.ID { //       telegramBot.updateUser(User{update.Message.Chat.ID, update.Message.Contact.PhoneNumber}, update.Message.Chat.ID) //   telegramBot.deleteContactRequestID(update.Message.Chat.ID) //  ChatID    msg := tgbotapi.NewMessage(update.Message.Chat.ID, "!") msg.ReplyMarkup = tgbotapi.NewRemoveKeyboard(false) //   telegramBot.API.Send(msg) } else { msg := tgbotapi.NewMessage(update.Message.Chat.ID, " ,   ,   !") telegramBot.API.Send(msg) telegramBot.requestContact(update.Message.Chat.ID) } } else { msg := tgbotapi.NewMessage(update.Message.Chat.ID, "      ,     !") telegramBot.API.Send(msg) telegramBot.requestContact(update.Message.Chat.ID) } } //      func (telegramBot *TelegramBot) updateUser(user User, chatID int64) { err := Connection.UpdateUser(user) if err != nil { msg := tgbotapi.NewMessage(chatID, " !    !") telegramBot.API.Send(msg) return } } //  ChatID   ? func (telegramBot *TelegramBot) findContactRequestID(chatID int64) bool { for _, v := range telegramBot.ActiveContactRequests { if v == chatID { return true } } return false } //  ChatID    func (telegramBot *TelegramBot) deleteContactRequestID(chatID int64) { for i, v := range telegramBot.ActiveContactRequests { if v == chatID { copy(telegramBot.ActiveContactRequests[i:], telegramBot.ActiveContactRequests[i + 1:]) telegramBot.ActiveContactRequests[len(telegramBot.ActiveContactRequests) - 1] = 0 telegramBot.ActiveContactRequests = telegramBot.ActiveContactRequests[:len(telegramBot.ActiveContactRequests) - 1] } } } 

Our bot is ready to go! It remains only to run it. To do this, write to main.go :

 var telegramBot src.TelegramBot func main() { src.Connection.Init() //     telegramBot.Init() //   telegramBot.Start() } 

As a result, we have got a bot, requesting the user's number, which will later be used in the system. Bot can and should be improved, add integration with the site, log in with one-time passwords, etc.

Undoubtedly, this system has disadvantages, the most obvious of which are: Telegram dependency (API change, blocking). For me, this is a good alternative to e-mail and sms, whether you will use it is up to you. Thanks for attention!

Source: https://habr.com/ru/post/331502/


All Articles