A Simple Telegram Time Tracker Bot Creation
Learn how to create a simple in Telegram with a primitive time tracker, a simple case of interaction with the Telegram API.
Join the DZone community and get the full member experience.
Join For FreeTelegram nowadays is a convenient, easy-to-use, intuitive, and secure messenger — and of course we all love stickers. Besides the personal messaging, we often use group chats with family, friends, and colleagues. In addition to live ordinary users, there are also bots on Telegram. They are created to automate replies, meaning the bot responds to specific messages (commands) and performs certain actions. An action can be either a simple greeting in response or a chain of certain questions and answers to perform specific logic operations.
Personally, I, for instance, constantly use @vkmusic_bot_news chatbot. It’s a simple bot for music searching and listening. A user sends a message with the name of a composition or the author and the bot provides variants that match the request.
In my example, I asked for a song «show must go on» and received several variants to choose from. Having chosen the first variant, I received a track in the next message. It’s convenient that you can listen to music right in the chat with the bot. In such a way a bot can fully substitute a third-party app, like a player on your phone. You just search and listen to the music right away.
So, we can see that the Telegram chatbots are a rather convenient and multifunctional feature of the messenger. That’s why this article is devoted to a simple chatbot creation. I decided to make a primitive time tracker to show you an example. It’s the simplest case of interaction with the Telegram API.
Simple Telegram Chatbot Creation
So let’s start.
You can find the docs here: https://core.telegram.org/bots/api.
First, you should create and register the bot in the Telegram. Let’s find the all-bots Father @BotFather. It’s a bot for bot registration.
We inform him that we want to create our own chatbot:
xxxxxxxxxx
/newbot
With the next request, he asks to create a name for the bot. Since my bot will track time, I give him the corresponding name and write:
xxxxxxxxxx
timeTrackerBot
The next step is to create the bot’s username (it will be used for search @username). The condition is that the username must end in bot or _bot. I write:
xxxxxxxxxx
my_time_tracker_bot
It’s ready! We receive a token in response, which means that we have registered a new chatbot.
Development
To start, I decided to look at what libraries the internet offers to us. The variants are multiple. The full list of the proposed options can be found here. My choice was TelegramBotApiBundle for Symfony. We install it:
xxxxxxxxxx
composer require borsaco/telegram-bot-api-bundle
And proceed.
The bundle supports the work with several bots at a time; besides, there is the option of adjustment (sending only to the developer) and working through proxy. For the test example, we do not need much, so we remove what we do not need.
xxxxxxxxxx
config/packages/telegram.yaml
I also carried the token out into the variable APP_TELEGRAM_TOKEN в .env:
A Bit of Theory
Telegram API works in two modes: you can get updates from the server through getUpdates() method or adjust the webHook. The first variant is good because it’s extremely simple, but the drawback of it that you should constantly request the server whether there are any updates. The webHook variant allows you to not have to think about how to get the updates but to focus on their rendering. In this case, Telegram will send the updates itself to the URL we’ll indicate.
The advantage of the second approach is obvious.
To register a Webhook, we’ll do the following:
xxxxxxxxxx
$bot = $botService->getBot('timeTracker');
$bot->setWebhook(
[
'url'=>'https://myWebSite.com/webhook'
]
);
Webhook in the url value is a route, which we’ll make a bit later.
$botService
is an object of the service Borsaco\TelegramBotApiBundle\Service\Bot, which can be injected in any place of the project.
Important: Telegram API only supports sending to https!
Let’s now check our Webhook. If you send a message to our Telegram bot, it will send us such a dataset in response:
xxxxxxxxxx
{
"update_id": 21406673,
"message": {
"message_id": 24,
"from": {
"id": 701891111,
"is_bot": false,
"first_name": "aleksei",
"language_code": "ru"
},
"chat": {
"id": 701891111,
"first_name": "aleksei",
"type": "private"
},
"date": 1580672814,
"text": "/help",
"entities": [
{
"offset": 0,
"length": 5,
"type": "bot_command"
}
]
}
}
We are interested in the part with the message text. In this case, it is clear that I sent the bot «/ help».
Naturally, he does not answer.
The presence of entities in the response indicates that the message was perceived by the bot as a command (everything that starts with a slash and is written in Latin is a command for Telegram).
Let’s create a controller. It will be the entry point for the requests from the Telegram API where to the updates will come.
For convenience, I put all the logic into the MessageProcessor service, where I pass the string received from Telegram.
The essence is simple. There are 4 commands: help, start, stop, report.
To the «help» message or any other one that does not fit into this list, the bot should return a message with a list of the commands available.
Each command presupposes specific behavior.
There are also two situations when the answer will tell the user that this action is prohibited at the moment (until the time tracker is stopped — you can’t start a new one. Accordingly, while there is no activity, you can’t stop anything either.)
I have added the following entities:
- User, which has the fields name, telegramId, and collection timeLines.
- TimeLine, which has a starting date and an end date startedAt, stopedAt.
That is, a user can have multiple timelines (which have a start time and a stop time).
We get a JSON string, and the first thing I do is decode the string and get the object.
xxxxxxxxxx
$response = \json_decode((string)$telegramUpdate);
Further on, I check if there is such a user in the database (the data about the user who wrote to the bot is taken from response. > message > from). If there is no such a user, we create it.
Since we want that «help» and «/ help» commands to be perceived by the bot in the same way, we translate the text of the message from the user into lowercase and delete the normal and the backslashes.
xxxxxxxxxx
$messageText = mb_strtolower($response->message->text);
$messageText = str_replace([’\\’, ’/’], ’’, $messageText);
Now we check the received command — if it’s included in the list of commands that we can process. And now, based on what we’ve got, we send a reply.
xxxxxxxxxx
$messageCommand = $this->isSupports($messageText) ? $messageText : false;
If it’s either a «start» or «stop» command, we create a TimeLine for this user or end the current one accordingly and inform the user about it.
If this is a «report», we calculate the time in all timeline for today and send the total number of hours and minutes to the user. We send the messages with the sendMessage method, which accepts an array of parameters. Required parameters are: chat_id and text.
A complete list of commands can be found here.
Since this is a test case, I limited myself to a simple switch / case for command selection.
xxxxxxxxxx
switch ($messageCommand) {
case self::HELP_COMMAND :
$this->bot->sendMessage(['chat_id' => $user->getTelegramId(), 'text' => self::ANSWERS[self::HELP_COMMAND]]);
break;
case self::START_COMMAND :
if ($this->timelineService->doesActiveExist($user)) {
$this->bot->sendMessage(['chat_id' => $user->getTelegramId(), 'text' => self::BAD_ANSWERS['existNotStoppedTimeLine']]);
break;
}
$this->telegramService->startTimeForUser($user);
$this->bot->sendMessage(['chat_id' => $user->getTelegramId(), 'text' => self::ANSWERS[self::START_COMMAND]]);
break;
case self::STOP_COMMAND :
if ($this->timelineService->doesActiveExist($user)) {
$this->bot->sendMessage(['chat_id' => $user->getTelegramId(), 'text' => self::ANSWERS[self::STOP_COMMAND]]);
break;
};
$this->bot->sendMessage(['chat_id' => $user->getTelegramId(), 'text' => self::BAD_ANSWERS['timeLineNotFound']]);
break;
case self::REPORT_COMMAND :
$timeForToday = $this->timelineService->getTodayTotalByUser($user);
$this->bot->sendMessage(['chat_id' => $user->getTelegramId(), 'text' => \sprintf(self::REPORT_COMMAND, $timeForToday)]);
break;
default:
$this->bot->sendMessage(['chat_id' => $user->getTelegramId(), 'text' => self::ANSWERS[self::HELP_COMMAND]]);
}
General view of the service is like this:
Thus, we’ve got a bot that can help you track the time in course of the day.
Conclusion
To draw a line, we can safely say that the Telegram API is quite functional and easy to master. A big advantage is good documentation and the ready-made libraries available for the usage.
Published at DZone with permission of Oleksandra Liubytska. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments