Pantagram

Carlo Casetta
9 min readFeb 3, 2021

A not so tech dive inside Telegram

Every single person who’s using the most famous message app named Whats’app received an advice from whatsapp about privacy policies changes starting from February 8 2021. The main rival platform, Telegram, in the next few days surpassed over 500 milion users.

Here you can find a user-perspective comparison table, but IT-tech people, knows Telegram as a framework, the holy-grail and open source framework for chatbot, a hybrid product, that bridges messaging app to social network.

I’m going to build a simple chatbot example, with a very few lines of code in a way tha you or your 13-year-old sun can replicate to build, inside Telegram, an expense tracker or a last-minute hotel advertise. If you’re not interested in coding experiences, reading how a chatbot is realized, you’ll understand (I hope so), that privacy is more a matter of users behaves than app or platform themselves.

This article is not intended to be a state of the art of modern coding techniques: it will follow the KISS design principle so to obtain the result in the quick and dirty way, aiming to be well understandable.

So that’s what you need to follow this adventure: a smartphone with Telegram installed, google account (gmail).

We’ll learn how to create and instruct your personal Telegram BOT. A BOT is a Telegram account that can answer message or request; how it works? We’ll arrange a script able to waiting to special message (commands) and answer with pop-up while people digits the messages. The script will reside on your google cloud for free.

We’ll implement two BOT abilities:

  1. Retrieving verses from bible

2. Scanning events calendar in the period requests and eventually requests for a booking.

You can try in any Telegram Chat the first ability asking to account U2GodBOT in the following way

digit @U2GodBOT genesis 1:1, for example

And you can try the second one asking for a period with this date-format (dd.mm:dd.mm) in this way

asking for scanning events of a period in the format dd.mm:dd.mm

If you click, an entry will be saved in a spreadsheet: so the BOT creator will know that your account asked for booking: the BOT knows your Telegram account, your personal chatid and the chat from which you’ve asked for information.

So, it’s time to start.

First you need your own personal BOT: in google you’ll find plenty of instructions on how to do it. If you want to try yourself, you’ve only have to search for Botfather account in Telegram app and send a /newbot message.

Just follow the instructions (you have to choose a name and account for the BOT) and, at the end, take note of your token value.

Now you can navigate to your google drive and create a new document “Google Apps Script”.

The script will be published as a webapplication and google will host it.

We’ll use the webhook technique to keep Telegram BOT and your script syncronized. With webhook your script wakes up when Telegram redirects messages users send to your BOT; using the google capabilities, all Telegram requests for the endpoint (your app-scripts webapp), are satisfied.

Let’s start. Write, inside your code.gs file

var token = "YOUR_BOT_TOKEN";
var telegramUrl = "https://api.telegram.org/bot" + token;
/*
---- Has to be published as web app
*/
function doPost(e) {if (e.postData.type == "application/json") { try { var update = JSON.parse(e.postData.contents); }
catch (e) {
throw e; }}return 200;}

So we’ve setup a minimal function that’s able to receive the updates from Telegram. Telegram sends updates in popular JSON format. We’ll react to inline_query update requests.

In order to setup webhook, we have to deploy your script. The first time you deploy the script, google asks the type (you have to answer Webapp) and asks for permissions: to let Telegram invoke your webapp doPost function, you’ve to publish the webapp to anyone (user anyone, i.e. not-logged-in).

Then click on Deploy and google will give you the public URL: copy that.

Then complete the global section of your script with the following instructions

var token = "YOUR_TOKEN"var telegramUrl = "https://api.telegram.org/bot" + token;var gswebAppUrl = "YOUR_WEBAPP_URL";
function setWebhook() {
var url = telegramUrl + "/setWebhook?url=" + gswebAppUrl; var response = UrlFetchApp.fetch(url); Logger.log(response);}

From the control bar of google choose set webhook function and then click Run.

You should receive in the log

{"ok":true,"result":true,"description":"Webhook was set"}

Perfect, goob job: your webapp now receives the posts users send to your BOT.

You can now implement the first feature of your BOT: find the Bible verses.

Our model need the first class to store our verse object: it contains three properties: a title, a description and the text itself.

/*(title, description, text) */class TheVerse {  constructor(title, description, text) {   this.title = title;   this.description = description;   this.text = text; }}

We’ll implement an API call to the services exposed by Bible-api website and we’re going to use the following schema to get a single verse

https://bible-api.com/BOOK CHAPTER:VERSEhttps://bible-api.com/john 3:16

Copy the following function

function bibleApiSearch(query) { query = query || 'Genesis 1:1'; var data = ""; var url = 'https://bible-api.com/' + query; try {  data = JSON.parse(UrlFetchApp.fetch(url).getContentText()); } catch (e) {  data = query + ": not found"; } return data;}

If you want, you can easily test this function: all you have to do inside google script is clicking near the first line of the function so you put a breakdown in your code in this way

Then you choose from the dropdown in the control-bar the bibleApiSearch function in this way

When you press debug the code run until your breakdown: then it stops and you can check on the right the variables-stack

everything is undefined. now if you press the down arrow button, you execute lines of codes one by one and you can check everytime the variations on the variables stack.

After the first line, the query variable assumes the value of “Genesis 1:1”: according with the schema we saw before, the Bible-APi web site should return the first verse of he first chapter of the Genesis book.

Let’s go forward until function-return instruction: in the variables stack you should see the following result.

I think that’s a good starting point!

Testing the first ability of our BOT

Before testing our new shining function with Telegram our model needs to know how to handle a bot object. The bot object will receive the telegram request from the doPost trigger, call the Bibleapisearch function and call the Telegram API to send the inline response.

The inline response is something different from a normal Telegram Message: it appears to the user as a pop-up hint and it can be recall from any Telegram chat, also outside from the chat of your personal BOT.

Here follows the code I prepare for the BOT class.

class Bot {constructor(token, update) {this.token = token;this.update = update;}inLineSearch(InLineDigit) {var query = InLineDigit || 'Genesis 1:1';// Check if the search string is complete before calling API regexp .*[0-9]+:[0-9]+if (RegExp("[A-Za-z][A-Za-z].* [0-9]+:[0-9]+").exec(InLineDigit)) { var data = bibleApiSearch(InLineDigit); try {  var verse = new TheVerse(query, data.text.slice(0, 256), data.text); var results =[{"id": "1", "type": "article", "title": verse.title, "description": verse.description, "input_message_content": { "message_text": verse.text }}];}catch (e) {Logger.log([new Date(), e.message, JSON.stringify(results), verse]);}
this.replyInLine(results);
}
}
replyInLine(data) {var options = {method: "post",payload: {chat_id: String(this.update.inline_query.from.id),results: JSON.stringify(data),inline_query_id: this.update.inline_query.id},};this.postTelegram("answerInlineQuery", options)}/*---- send to telegram the response--------*/postTelegram(method, options) {// ss.appendRow([new Date(), JSON.stringify(options), options, telegramUrl + '/' + method, options]);try {var request = UrlFetchApp.fetch(telegramUrl + '/' + method, options);}catch (e) {Logger.log([new Date(), e.message, JSON.stringify(results), verse]);}}}

Now it’s time to complete the doPost google trigger and try to call our new shining function.

function doPost(e) {if (e.postData.type == "application/json") {  try {   var update = JSON.parse(e.postData.contents);   var bot = new Bot(token, update);   if (update) {    if (update.hasOwnProperty('inline_query')) {      bot.inLineSearch(update.inline_query.query);    }   }
catch (e) {
e = (typeof e === 'string') ? new Error(e) : e; Logger.log(e.name, e.messsage,e.lineNumber); throw e; }} return 200;
}

The Telegram update message, in an inline search has a particular property valorized: inline_query; so we have to examine the content of this inline query.

Ok. we’re ready to deploy our google script: you’ve to follow the same procedure above releasing a new deployment.

Then open telegram and test with a classic Genesis 1:1.

It’s done. Let’s go to step 2.

Scanning google calendar from a telegram booking request

Our point of control is inside the Bot class in the method inLineSearch.

We have to add an appendix to manage another type of query to handle a request formatted as dd.mm:dd.mm. Then we’ll search in the google calendar if any events are already present in the time frame. If we find no events, then we’ll answer that the period is free and the user can send a booking request.

Scanning the events calendar we’ll use the google API in the following way

function CalGASSearch(query) {
var bookingcalendar = CalendarApp.getDefaultCalendar();
free = false;
var daterange = parseDate(query);if (daterange) {events = bookingcalendar.getEvents(daterange[0], daterange[1]);}if (events.length == 0) {free = true;}return free;}

So complete the InlineSearch method.

inLineSearch(InLineDigit) {var query = InLineDigit || 'Genesis 1:1';// Check if the search string is complete before calling API regexp .*[0-9]+:[0-9]+if (RegExp("[A-Za-z][A-Za-z].* [0-9]+:[0-9]+").exec(InLineDigit)) {var data = bibleApiSearch(InLineDigit);try {var verse = new TheVerse(query, data.text.slice(0, 256), data.text);var results =[{"id": "1", "type": "article", "title": verse.title, "description": verse.description, "input_message_content": { "message_text": verse.text }}];}catch (e) {Logger.log([new Date(), e.message, JSON.stringify(results), verse]);}this.replyInLine(results);}/* dd.mm:dd.mm) */if (RegExp("(^0?[1-9]|[12][0-9]|3[01])\.(0?[1-9]|1[012]):(0?[1-9]|[12][0-9]|3[01])\.(0?[1-9]|1[012])").exec(InLineDigit)) {var free = CalGASSearch(InLineDigit);try {var response = "The period request is already booked. Please search for a different date range";if (free) {response = String(query) + ": The period request is free. Click to send a booking request";}var results =[{"id": "1", "type": "article", "title": query, "description": response, "input_message_content": { "message_text": response }}];}catch (e) {Logger.log([new Date(), e.message, JSON.stringify(results), verse]);}this.replyInLine(results);}}

And then we’ll handle the user click event with a new method inside the BOT class.

//writes to spreadsheet a booking requestask4booking() {
var ss = SpreadsheetApp.openById('YOUR_SPREADSHEET_ID').getSheets()[0];
ss.appendRow([new Date(), this.update.message.from.last_name, this.update.message.from.first_name, this.update.message.chat.id, this.update.text]);}

You have to extract the id of your spreadsheet from the URL as described here.

Then adjust a little the doPost function adding the following lines of code

if (update.message && update.message.hasOwnProperty('via_bot') && update.message.text.includes("free.")) {bot.ask4booking();bot.reply("Thanks, your request will be processed as soon as possible");}

We are looking for a special property of the message: the via_bot property. This is filled only when a user interact with an inline response.

Well, done.

With this few lines I want to share the following concepts.

  1. Today is very easy and very powerfull interact with a series of micro functionality avaiable from many vendors. In order to achive all the possibilities without limitations the secret is follow the open products (open source products). From this point of view, Telegram is better than Whats’up.
  2. Many requests can be satisfied mantaining a KISS profile: implementing standards today can be very demanding in term of complexity and we always have to ask ourselves: do I really need all of this stuff?
  3. Privacy really matters but it depends more on user behaves than in the app you use (for example in a telegram BOT you give to developer all of your account datas).

Thanks for reading all the article!

--

--