Внезапно появилась задача сделать телеграм бота, который бы отсылал напоминания о предстоящих мероприятиях (дополнительные занятия, факультативы, семинары и так далее) в школьно-родительскую телеграм группу.
ТЗ
Есть группа, есть родители, есть их дети. Родителям в группу должно приходить напоминание, что, например, завтра произойдет Мероприятие «Х» с 14.00 до 15.00. Рассылка должна приходить ежедневно, в случае наличия таковых мероприятий на завтра. Мероприятия приходят от учителя.
Предварительные шаги
Из-за того, что данные могут приходить в разном формате и виде, было принято решение заносить их в расшаренный гугл календарь.
Это удобно по ряду причин:
- Унификация и систематизация данных
- Избегание дополнительного ручного труда при занесении или переносе данных — доступ к календарю есть с любого телефона.
Гугл календарь
Был создан дополнительный гугл календарь, к нему дан доступ жене — пока вносить будет она.
Так же из него получен Id, который понадобится в дальнейшем в скриптах:
Гугл скрипт взаимодействия бота с календарем — календарная часть
function searchDay() {
const searchDay = new Date();
searchDay.setDate(searchDay.getDate() + 2);
return searchDay;
}
function getCalendarEvents() {
const today = new Date()
const schoolCalendar = CalendarApp.getCalendarById(CAL_ID);
const eventsForDay = schoolCalendar.getEvents(today, searchDay());
const eventsArr = [];
const optionLocaleObject = { timeStyle: "short" }
if (eventsForDay.length !== 0) {
for (let i = 0; i < eventsForDay.length; i++) {
let formatedDay = eventsForDay[i].getStartTime().toLocaleDateString('ru-RU')
let startTime = eventsForDay[i].getStartTime().toLocaleTimeString('ru-RU', optionLocaleObject)
let endTime = eventsForDay[i].getEndTime().toLocaleTimeString('ru-RU', optionLocaleObject)
let eventDescription = eventsForDay[i].getDescription()
let eventTitle = eventsForDay[i].getTitle()
eventsArr.push([eventTitle, formatedDay, startTime, endTime, eventDescription])
}
}
return eventsArr
}
searchDay()
возвращает дату — послезавтра.
getCalendarEvents()
собирает в массив все данные из календаря за сегодня и завтра через schoolCalendar.getEvents(today, searchDay());
— получает все события, происходящие в заданном временном диапазоне. Этот метод возвращает события, которые начинаются в указанном временном диапазоне, заканчиваются в этом временном диапазоне или охватывают временной диапазон.
Скрипт — подготовка данных для телеграма
function filteredArrToText() {
const filteredArr = getCalendarEvents();
const beautyArr = filteredArr.map(row => [`📒 "${row[0]}" состоится ${row[1]}, начало в ${row[2]} до ${row[3]}, детали: ${row[4]}`])
return (beautyArr.join('\n\n'))
}
function eventsCheckerToSend() {
const text = filteredArrToText()
if (text.length !== 0) { // если длина текста не равна 0 - т.е. там есть что отправлять
let messageText = ` Мероприятия на сегодня и завтра:\n`
sendMessage(GROUP_ID, (messageText + text)) // отправка сообшения
}
}
filteredArrToText()
приводит массив данных в текст — для передачи в телеграм.
eventsCheckerToSend()
вешается на триггер и если массив не пустой — каждый день отправляет текст в группу телеграма.
Выглядит это следующим образом:
Скрипт телеграм бота
Так как само написание телеграм бота рассматривалось на этом сайте много раз, ниже привожу код без дополнительных комментариев.
Общий код
// Установка вебХука в телеграме
function setWebHook() { //выполняется единожды - установить вебХук
const url = telegramUrl + "setWebhook?url=" + googleUrl;
const response = UrlFetchApp.fetch(url).getContentText();
const textResponse = JSON.parse(response);
console.log(textResponse)
}
// Удаление вебХука в телеграме
function deleteWebHook() { //выполняется единожды - удалить установленный выше вебХук
const url = telegramUrl + "deleteWebhook?url=" + googleUrl;
const response = UrlFetchApp.fetch(url).getContentText();
const textResponse = JSON.parse(response);
console.log(textResponse)
}
// основная функция, которая обрабатывает входящие данные от телеграма
function doPost(e) {
try {
const main = JSON.parse(e.postData.contents); // получаем данные из телеграм бота
// вытаскиваем все данные из contents
const chatId = main.message.chat.id;
const firstName = main.message.chat.first_name;
const lastName = main.message.chat.last_name;
const messageText = main.message.text;
const arrayText = messageText.split(" "); // массив для последующей обработки команд
const detailsArray = [chatId, firstName, lastName, messageText, arrayText]; //собираем все что выше массив
const objToTransfer = Object.assign({}, detailsArray); // делаем из массива объект для передачи
analyseDetails(objToTransfer);
}
catch (error) {
sendMessage(ADMIN_ID, error)
}
}
Back-end часть телеграм бота
function analyseDetails(objReceived) { // анализ того, что пришло со стороны телеграма
const receivedCommand = objReceived[4][0].toLowerCase(); // "4": ["/list", "", "" и тд]
switch (receivedCommand) { //если пришла команда
case '/start':
sendStartMessage(objReceived);
break;
case '/help':
sendStartMessage(objReceived);
break;
default: // если пришло что-то отличное от команды
onModer(objReceived);
break;
}
}
function sendStartMessage(obj) {
const userId = obj[0]; //Юзер id
const startMessage = `🤖 Привет! 🤖\n\n Я - бот, присылающий напоминания о предстоящих мероприятиях на сегодня и завтра.\n\n Весь календарь мероприятий доступен по ссылке ${SITE_URL}`
sendMessage(userId, startMessage);
}
// если пришло что-то отличное от команды - отправить администратору бота
function onModer(obj) {
const userId = obj[0]
const userName = obj[1]
const userSurname = obj[2]
const userMessage = obj[3]
const text = `Пользователь ${userName} ${userSurname} с ID ${userId} послал на модерацию сообщение: ${userMessage}`
sendMessage(ADMIN_ID, text)
sendMessage(userId, 'Ваше сообщение отправлено администратору бота')
}
Базовый метод отправки сообщения
function sendMessage(chatid, chatText) {
const chatId = chatid;
const text = chatText;
// const chatId = 309144243;
// const text = 'Test text';
const payload = {
"method": "sendMessage",
"chat_id": String(chatId),
"text": text,
"parse_mode": 'HTML',
"disable_web_page_preview": true
};
const data = {
"method": "post",
"payload": payload
};
UrlFetchApp.fetch(telegramUrl, data);
}
Ну и напоследок — отдельно объявленные глобальные переменные
// КАЛЕНДАРЬ//
const DAYS_NUM = 2
const DAYS_WEEK = 7
const CAL_ID = 'ID КАЛЕНДАРЯ'
// ТЕЛЕГРАМ //
const botToken = 'botToken, полученный от BotFather';
const telegramUrl = "https://api.telegram.org/bot" + botToken + "/";
const googleUrl = "ссылка на развернутый webApp"
const ADMIN_ID = ваш_ID;
const GROUP_ID = -ID группы куда будет вещать бот;
Так же хочется обратить внимание, что Id группы в телеграме начинаются со знака минус «-«. Это просто — чтоб не пугаться 🙂
Для того, чтобы не путаться где и что, я обычно разношу это по разным блокам-файлам:
Ваше мнение важно и может улучшить блог
Я хочу услышать ваше мнение и ваши идеи о том, как сделать этот сайт еще лучше. Примите участие в опросе, чтобы поделиться вашими пожеланиями, предложениями и замечаниями. Пройдите опрос сейчас и помогите сделать этот сайт более полезным для вас!