Гугл календарь и напоминания в школьную телеграм группу

Внезапно появилась задача сделать телеграм бота, который бы отсылал напоминания о предстоящих мероприятиях (дополнительные занятия, факультативы, семинары и так далее) в школьно-родительскую телеграм группу.

ТЗ

Есть группа, есть родители, есть их дети. Родителям в группу должно приходить напоминание, что, например, завтра произойдет Мероприятие «Х» с 14.00 до 15.00. Рассылка должна приходить ежедневно, в случае наличия таковых мероприятий на завтра. Мероприятия приходят от учителя.

Предварительные шаги

Из-за того, что данные могут приходить в разном формате и виде, было принято решение заносить их в расшаренный гугл календарь.

Это удобно по ряду причин:

  • Унификация и систематизация данных
  • Избегание дополнительного ручного труда при занесении или переносе данных — доступ к календарю есть с любого телефона.

Гугл календарь

Был создан дополнительный гугл календарь, к нему дан доступ жене — пока вносить будет она.

Так же из него получен Id, который понадобится в дальнейшем в скриптах:

google calendar 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() вешается на триггер и если массив не пустой — каждый день отправляет текст в группу телеграма.

Выглядит это следующим образом:

telegram bot message

Скрипт телеграм бота

Так как само написание телеграм бота рассматривалось на этом сайте много раз, ниже привожу код без дополнительных комментариев.

Общий код

// Установка вебХука в телеграме
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 группы в телеграме начинаются со знака минус «-«. Это просто — чтоб не пугаться 🙂

Для того, чтобы не путаться где и что, я обычно разношу это по разным блокам-файлам:

google scripts files

Ваше мнение важно и может улучшить блог

Я хочу услышать ваше мнение и ваши идеи о том, как сделать этот сайт еще лучше. Примите участие в опросе, чтобы поделиться вашими пожеланиями, предложениями и замечаниями. Пройдите опрос сейчас и помогите сделать этот сайт более полезным для вас!

Добавить комментарий