Telegram bot with Golang and Mongodb
Tags: telegrambot, go, bot, mongodb
Published: 2022-09-05 19:16:03

So over the weekend I was working on a telegram bot whose task is to manage a particular telegram group. Wondering what the bot does?

1. The bot welcomes newly added users to the telegram group
2. Deletes links sent to the group by the users aside from the Admin
3. Deletes every messages sent to the group by new users until they have added a certain number of users to the group and after words they can send messages to the group

In this article, I would be showing you how to create a telegram bot with Golang and Mongodb. First search for "botfather" on telegram and create a newbot. After you have set a name for you bot and a username, a token would be sent to you. This token would be used to authenticate your bot.

This is the .env config:

```ssh
TOKEN=<generated token from botfather in telegram>

USER_NAME=<the group admin username>

MONGO_URI=mongodb://localhost:27017<for local host mongodb>
DATABASE_NAME=<database name>

```

This is the code for the bot:

```go
package tele

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
	"github.com/iqquee/telebot/database"
	"go.mongodb.org/mongo-driver/bson"
)

func urlChecker(character string) bool {
	var val bool
	//check if the string contains a .
	if strings.Contains(character, ".") {
		for i, value := range character {
			//get the index of .
			if string(value) == "." {
				fmt.Printf("%d - %v\n", i, string(value))
				prev := i - 1
				next := i + 1
				for e, v := range character {
					//check the previous character if its an "" string
					if e == prev {
						if string(v) != " " && string(v) != "." {
							//check the next character if its an "" string
							for ee, vv := range character {
								if ee == next {
									if string(vv) != " " && string(vv) != "." {
										val = true
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return val
}

func Bot() {
	token := os.Getenv("TOKEN")
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	bot.Debug = true

	log.Printf("Authorized on account %s", bot.Self.UserName)

	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60

	updates := bot.GetUpdatesChan(u)

	for update := range updates {
		if update.Message != nil {
			log.Printf("[%s] %s\n", update.Message.From.UserName, update.Message.Text)


			// THESE APPLIES TO EVERYONE IN THE GROUP EXCEPT THE ADMIN OF THE GROUP
			foundUser := update.Message.From.UserName
			if foundUser != os.Getenv("USER_NAME") {

				//welcome new users
				wc := update.Message.NewChatMembers
				if wc != nil {
					var byt []map[string]string

					jsonM, _ := json.Marshal(wc)

					json.Unmarshal(jsonM, &byt)
					for val := range byt {
						if byt[val]["first_name"] != "" {
							firstname := byt[val]["first_name"]

							sendMsg := fmt.Sprintf("your message")
							msg := tgbotapi.NewMessage(update.Message.Chat.ID, sendMsg)

							bot.Send(msg)
						}
					}
				}

				if update.Message.NewChatMembers != nil {

					up := update.Message
					var addedUsers database.AddedUsers
					jsonr, _ := json.Marshal(up)

					json.Unmarshal(jsonr, &addedUsers)
					insertID, _ := database.CreateMongoDoc(database.UserCollection, addedUsers)
					fmt.Printf("Mongodb data created with ID: %v\n", insertID)

				}

				usersFirstname := update.Message.From.FirstName
				//delete messages that contains link sent by other users aside from the admin
				domain := urlChecker(update.Message.Text)
				if domain {
					
					deleteMsg := tgbotapi.NewDeleteMessage(update.Message.Chat.ID, update.Message.MessageID)
					bot.Send(deleteMsg)

					//notify they user that links can't be sent to the group
					sendMsg := fmt.Sprintf("%s The message you sent contains a link or you failed to add a space after the full stop(.). Links cannot be sent to this group", usersFirstname)
					msg := tgbotapi.NewMessage(update.Message.Chat.ID, sendMsg)

					bot.Send(msg)
				} else { //if the messages sent to the group is not a link

					//check if the text message sent is not empty
					if update.Message.Text != "" {
						//check if the user have already added _ number of users to the group
						countFilter := bson.M{"from.firstname": update.Message.From.FirstName}
						addedUserCount := database.CountCollection(database.UserCollection, countFilter)
						fmt.Printf("This is the number of users you have added to the group %v\n....", addedUserCount)
						userNum := 5
						if addedUserCount < userNum {
							// delete the messages sent to the group by the user who have not added the set numbers of users
							deleteMsg := tgbotapi.NewDeleteMessage(update.Message.Chat.ID, update.Message.MessageID)
							bot.Send(deleteMsg)

							fmt.Println(deleteMsg)
							// and if not delete their message and notify them to first add _ numbers of users before they can send in messages
							usersToAdd := userNum - addedUserCount
							sendMsg := fmt.Sprintf("%s you have only added %v user(s). You need to add %v more user(s) to be able to send messages to this group. If you can't follow the process send a DM to @EXODUSTV to pay #500 and get verified to the VCF file", usersFirstname, addedUserCount, usersToAdd)
							msg := tgbotapi.NewMessage(update.Message.Chat.ID, sendMsg)
							// msg.ReplyToMessageID = update.Message.MessageID
							bot.Send(msg)
						}
					}
				}

			}

		}
	}
}

```

This is the mongodb code:

```go
package database

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/joho/godotenv"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)


var (
	UserCollection  *mongo.Collection = OpenCollection(Client, "users")
)

type AddedUsers struct {
	From           From             `json:"from"`
	NewChatMembers []NewChatMembers `json:"new_chat_members"`
}

type From struct {
	ID        int64  `json:"id"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Username  string `json:"username"`
}

type NewChatMembers struct {
	ID        int64  `json:"id"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Username  string `json:"username"`
}


func DbInstance() *mongo.Client {
	if err := godotenv.Load(); err != nil {
		log.Println("no env gotten")
	}
	MongoDb := os.Getenv("MONGO_URI")
	client, err := mongo.NewClient(options.Client().ApplyURI(MongoDb))
	if err != nil {
		log.Fatal(err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	err = client.Connect(ctx)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("successfully connected to mongodb")
	return client
}

var Client *mongo.Client = DbInstance()

func OpenCollection(client *mongo.Client, collectionName string) *mongo.Collection {
	if err := godotenv.Load(); err != nil {
		log.Println("no env gotten")
	}
	databaseName := os.Getenv("DATABASE_NAME")
	var collection *mongo.Collection = client.Database(databaseName).Collection(collectionName)
	return collection
}

func GetMongoDoc(colName *mongo.Collection, filter interface{}) (*AddedUsers, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	var data AddedUsers

	if err := colName.FindOne(ctx, filter).Decode(&data); err != nil {
		return nil, err
	}

	return &data, nil
}

func GetMongoDocs(colName *mongo.Collection, filter interface{}, opts ...*options.FindOptions) (*[]AddedUsers, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	var data []AddedUsers

	filterCusor, err := colName.Find(ctx, filter, opts...)
	if err != nil {
		return nil, err
	}

	if err := filterCusor.All(ctx, &data); err != nil {
		return nil, err
	}

	return &data, nil
}

func CreateMongoDoc(colName *mongo.Collection, data interface{}) (*mongo.InsertOneResult, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	insertNum, insertErr := colName.InsertOne(ctx, data)
	if insertErr != nil {
		return nil, insertErr
	}

	return insertNum, nil
}

func CountCollection(colName *mongo.Collection, filter interface{}) int {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	count, err := colName.CountDocuments(ctx, filter)

	if err != nil {
		return 0
	}
	return int(count)
}

```

This is the code in my main.go file:

```go
package main

import (
	"log"

	"github.com/iqquee/telebot/tele"
	"github.com/joho/godotenv"
)

func main() {
	if err := godotenv.Load(); err != nil {
		log.Println(".env not found")
	}

	tele.Bot()
}

```
After which you are done building your bot, you would need to  deploy it to a server. Heroku doesn't work well with it so I would highly recommend you deploy your bot on [https://railway.app](https://railway.app). After your bot have been successfully deployed to the server, add your bot to the group you want it to manage for you and  then make the bot an admin in the group. Your bot is now set :)

I hope this helps you build your own telegram bot. You can checkout this GitHub repository [github.com/iqquee/telebot](https://github.com/iqquee/telebot) for the complete code.