DEV Community

Cover image for Telegram bot with Golang and Mongodb
Mathias Jiya
Mathias Jiya

Posted on • Edited on

Telegram bot with Golang and Mongodb

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:

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>

Enter fullscreen mode Exit fullscreen mode

This is the code for the bot:

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)
                        }
                    }
                }

            }

        }
    }
}

Enter fullscreen mode Exit fullscreen mode

This is the mongodb code:

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)
}

Enter fullscreen mode Exit fullscreen mode

This is the code in my main.go file:

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()
}

Enter fullscreen mode Exit fullscreen mode

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. 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 for the complete code.

Top comments (2)

Collapse
 
homavand profile image
mohammad babaha

Thanks for this

Collapse
 
iqquee profile image
Mathias Jiya

I'm glad you found this helpful