Уведомления из гугл календаря в телеграм
Некоторое время назад я столкнулась с проблемой ведения двух календарей: личного и рабочего. Точнее само ведение (планирование встреч, переносы, редактирование и т.п.) проблемы не вызывало, но я осознала, что в ежедневной суете у меня совершенно нет возможности / желания несколько раз залезать в календарь и проверять предстоящие встречи.
Естественно, я объединила оба календаря, дала права доступа через оба аккаунта на возможность видеть встречи друг друга, с учетом того, чтобы мой личный календарь не был виден аккаунтам, которые просматривают рабочий календарь, то бишь коллегам, заказчикам и прочим.
Но все равно я периодически пропускала уведомления о начале какого-либо события.
В общем, я пришла к тому, что мне лично очень удобно все делать через телеграм и было бы неплохо иметь бота, который присылал бы мне сообщение со ссылкой на встречу за 5-10 минут. Для меня лично это стало лучшим решением, которым я пользуюсь несколько месяцев и до сих пор не вижу дроубеков вообще.
Таким образом, я продолжаю пользоваться календарем: в личный календарь я вношу конфы и митинги по личным интересам, плюс онлайн-уроки; в рабочем планы строят обычно коллеги, что позволяет мне вообще его не открывать. Телеграм бот в свою очередь присылает полный план встреч на день и каждую отдельную встречу непосредственно перед началом из обоих календарей.
Реализация
Первым делом нужно обозначить видимость для обоих календарей. Для этого просто подписываемся на каждый из календарей из обоих аккаунтов по кнопке Добавить другой календарь

Далее выбираем Подписаться на календарь и вводим почту, на кого подписываемся. Я не буду подробно здесь останавливаться, возможно нужны дополнительные пермишены и подтверждения, но я уверена, что вы справитесь.
Как только видимость из обоих календарей настроена можно переходить к написанию кода. Моменты с созданием бота и проектом в App Script уже были обговорены здесь, поэтому сразу перейду к ключевым функциям.
Получение всех событий из календаря
В App Script есть класс CalendarApp , в котором мы используем метод getCalendarById(calendar_id) , calendar_id — это ваш gmail login.
Таким образом я сохраняю оба календаря в соответствующие переменные:
const calendar_ct = CalendarApp.getCalendarById(gmail_login_1) const calendar_ns = CalendarApp.getCalendarById(gmail_login_2)
Далее отфильтрую все события по дате, я хочу получить планы только на сегодня и использую метод getEventsForDay(date) . Также записываю их в переменные
const now = new Date(); const events_ct = calendar_ct.getEventsForDay(now); const events_ns = calendar_ns.getEventsForDay(now);
Полученные массивы просто объединяем в один методом concat() . При обращении к элементу массива мы увидим в консоли CalendarEvent . Чтобы вычленить подробности из CalendarEvent , нужно обратиться к каждому элементу и забрать нужную инфу, например, название, время начала, описание.
Для данного набора запрашиваемой информации мне нужно использовать методы getDescription(), getTitle(), getStartTime().
Помимо получения деталей события я их преобразую в нужный мне вид. Например, getStartTime() возвращает мне дату целиком и возвращаемое время не соответствует моему часовому поясу. Учитывая, что я хочу получить только время вида чч:мм, я преобразую время следующим образом
start_time = new Date(start_time.getTime() + (6 * 60 * 60 * 1000)) //6 - разница во времени между NY и Berlin
С описанием из события в календаре тоже не все так просто. При выводе в консоль я получаю не текст или ссылку в виде текста, как я ожидала, а текст и ссылки заключенные в теги.

И проблема заключается в отправке в телеграм. Чтобы все обработалось гладко и сообщение выглядело примерно следующим образом

я применила замену (я просто остановилась на решении, которое работает, не вдаваясь в детали) :
const regExp = /<(?!\/?a>|\/?a href|\/?br)[^>]+>/g; descr = descr.replace(regExp,'').replace(/
/g,`\n`).replace(/ /g,' ');
Все выбранные и преобразованные данные я вставила в новый массив для дальнейшей работы уже с ним. Вся функция целиком ниже.
/** * The function gets all events for today from 2 calendars and sorts them * * @return events_details_arr all sorted events for today */ function getEvents() < const calendar_ct = CalendarApp.getCalendarById(gmail_login_1) const calendar_ns = CalendarApp.getCalendarById(gmail_login_2) const now = new Date(); const events_ct = calendar_ct.getEventsForDay(now); const events_ns = calendar_ns.getEventsForDay(now); const events = events_ct.concat(events_ns); const regExp = /<(?!\/?a>|\/?a href|\/?br)[^>]+>/g; const events_details_arr = new Array(); events.forEach((el) => < let descr = el.getDescription().toString(); const title = el.getTitle(); let start_time = el.getStartTime(); start_time = new Date(start_time.getTime() + (6 * 60 * 60 * 1000)) //6 - разница во времени между NY и Berlin if (descr === '') < events_details_arr.push([title,start_time]); >else < descr = descr.replace(regExp,'').replace(/
/g,`\n`).replace(/ /g,' '); events_details_arr.push([title,start_time,`\n$`]); > >) bubble_sort(events_details_arr) return events_details_arr >
Да, здесь же я сортирую события по возрастанию времени их старта.
Отдельно я написала функцию, которая преобразует время в удобоваримый вид
/** * The function transforms the date into a string * * @param date The date to be transformed * @return time_str the time in the string form */ function time_to_string(date) < let h = new String(date.getHours()); let m = new String(date.getMinutes()); if (m.length == 1) < m = `0$` > const time_str = ` $:$`; return time_str >
Отправка в телеграм
Наконец, функции отправки в чат с ботом. Я разделила отправку на 2 отдельные функции: 1-я отправляет одно событие в чат за 5-8 минут до начала, 2-я отправляет все события списком в одном сообщении по порядку следования.
function send_next_event() < const today_events_arr = getEvents(); const cur_time = new Date(new Date().getTime() + (6 * 60 * 60 * 1000)) //6 - разница во времени между NY и Berlin let msg = new String(); for (i=0; i0.1) < today_events_arr[i][1] = time_to_string(today_events_arr[i][1]); if (msg == "") < msg = `$` > else < msg = `$\n$` > send(msg,chat_id_root,API); > > >
Функция send_next_event() проверяет разницу между текущим временем и стартовым временем каждого из событий в массиве и отправляет сообщение в чат ( send(msg,chat_id_root,API) ) примерно за 5 минут.
Понимаю, здесь очень странные манипуляции со значением времени, но вот так это выглядит в js. Я сама еще в этом плаваю, потому не хочу объяснять все детали, т.к. сама искала ответы онлайн касаемо этой части. В целом, идея была преобразовать время из 1.65286722566E12 во время вида 13:00 .
Функция для отправки всех событий представлена ниже.
function send_all_events() < const today_events_arr = getEvents(); let msg = new String(); if (today_events_arr.length !== 0) < today_events_arr.forEach((el,ind) => < el[1] = time_to_string(el[1]) if (msg == "") < msg = `$$` > else < msg = `$\n$ $` > >) send(msg, chat_id_root, API); > else < send('В календаре нет планов', chat_id_root, API); >>
Функция активируется по триггеру каждое утро, а также я могу запустить ее по команде из бота.



Слева на скрине примеры сообщений, которые я получаю от бота в течение дня. При этом описание в календаре есть только у второго события.
Заключение
Вот такой Reminder bot уровня минимум спасает меня каждый день. Как обычно буду рада вашим комментам и вопросам. Весь код целиком есть на гите, который я вот только начала вести (https://github.com/Nadezhda95).
Всем добра и нет войне.
Epical — Telegram бот для Google календаря
В какой-то момент я понял, что настраивать уведомления о событиях в календаре через системные уведомления не очень удобно: телефоны меняются, ноутбуки ломаются, появляются новые девайсы.
Особенно неприятно, если аккаунтов с календарями и устройств много — постоянно что-то забываешь подключить или что-то отваливается.
Гораздо удобнее подключить уведомления в Телеграм и получить их сразу на всех устройствах. Существующего решения я не нашел, так что пришлось написать свое.
Что умеет бот:
1. Уведомлять о предстоящем событии за 1 минуту, 5, 10 или 15 минут
2. Работать с несколькими аккаунтами
3. Работать с несколькими календарями в каждом аккаунте
4. Гибко отслеживать состояние события. Например, если у вас установлено уведомление за 1 минуту, а событие удалено за 2, бот это поймет.
5. Присылать кнопку для подключения к онлайн-митингу и данные об организаторе события.
Как это выглядит?
Вот пример, как оно будет работать в чате:
Интеграция Google Calendar + Телеграм
Соедините Google Calendar и Телеграм через веб интерфейс за 5 минут, без программистов и специальных знаний.


Создайте интеграцию Google Calendar и Телеграм самостоятельно, без программистов
Источник данных
Приемник данных
Другие готовые интеграции
Google Calendar (277 готовых коннекторов)
Телеграм (172 готовых коннектора)
Без ограничений
Получите 14-ти дневный
пробный доступ
Возможности автоматизации
Google Calendar и Телеграм
Настройте один раз правила, по которым будут работать системы.
С заданным интервалом передавайте данные из Google Calendar в Телеграм.

Источник данных: Google Calendar, доступные действия:
- Загрузить СОБЫТИЯ (измененные)
- Загрузить СОБЫТИЯ (измененные)
- Загрузить СОБЫТИЯ (новые)
- Загрузить СОБЫТИЯ (новые)
- Загрузить СОБЫТИЯ (отмененные)
- Загрузить СОБЫТИЯ (отмененные)
- Загрузить СОБЫТИЯ (по дате начала)
- Загрузить СОБЫТИЯ (по дате начала)
- Загрузить СОБЫТИЯ (по дате окончания)
- Загрузить СОБЫТИЯ (по дате окончания)
Приемник данных: Телеграм, доступные действия:
- Отправить СООБЩЕНИЕ
- Отправить СООБЩЕНИЕ
Популярные вопросы про интеграцию Google Calendar и Телеграм
Как происходит интеграция Google Calendar и Телеграм?
- Для начала нужно зарегистрироваться в ApiX-Drive
- Выбираете какие данные передавать из Google Calendar в Телеграм
- Включаете автообновление
- Теперь данные будут автоматически передаваться из Google Calendar в Телеграм
Сколько времени нужно на интеграцию?
В зависимости от системы, с которой вы будете делать интеграцию, время настройки может отличаться и составлять от 5-ти до 30-минут. В среднем настройка занимает 10-15 минут.
Сколько стоит интеграция Google Calendar с Телеграм?
За саму интеграцию ничего платить не нужно и на всех тарифах доступен полностью весь функционал. Вы оплачиваете только количество данных, которые по факту передаются из одной вашей системы в другую через наш сервис. Если у вас количество данных в месяц небольшое, можете смело пользоваться бесплатным тарифом или перейти на платный, при необходимости. Подробнее о тарифах.
Сколько всего готовых интеграций доступно в Apix-Drive?
На данный момент у нас готово 354+ интеграций помимо Google Calendar и Телеграм
Информация о Google Calendar
Предоставляемый совершенно бесплатно сервис Google Calendar предназначен для планирования деловых встреч и личных мероприятий. У пользователя есть возможность использовать сразу несколько календарей, внося в них самые разные события, единоразовые и повторяющиеся. Также есть возможность делиться событиями с другими пользователями и вести календари совместно. Google Calendar предоставляет возможность интеграции со сторонними сервисами и приложениями. Подробнее
Информация о Телеграм
Очень популярный во всём мире мессенджер Telegram предоставляет своим пользователям огромное количество возможностей. Помимо обычного обмена сообщениями и совершения голосовых звонков, можно создавать секретные чаты, каналы и группы. Наличие специального API даёт возможность разработки различных ботов. Продвинутая функциональность превратила Telegram в успешный канал для проведения рекламных кампаний, этот мессенджер охотно используется службами поддержки. Подробнее
Телеграм бот для Календаря Google
В этой статье мы расскажем, как создать Телеграм бота для планирования встреч при помощи Календаря Google. Наш бот будет помогать назначать встречи, учитывая доступность свободного времени.
Будет весьма неплохо, если у вас уже есть базовые знания о Python и HTTP-запросах, а также представление о google-calendar-api.
Начнем с того, что перейдем в Телеграм и найдем там Бота-Отца (BotFather). Этот бот предназначен для создания новых ботов и управления ими.

Далее введем следующие команды:
/start /newbot
После этого введем имя бота и имя пользователя. В результате будет создан бот и сгенерирован ключ API. Давайте проверим бот, послав ему сообщение.
У BotFather есть несколько опций для настройки нового бота:
/setname - change a bot's name /setdescription - change bot description /setabouttext - change bot about info /setuserpic - change bot profile photo /setcommands - change the list of commands
Но пока мы не будем усложнять наш проект и остановимся на создании нового бота.
Python-код
Далее создадим файл под названием main.py и сохраним туда следующий код:
import requests import datetime import json api_key='your_api_key' def run(): url = "https://api.telegram.org/bot<>/getUpdates".format(api_key) response = requests.get(url) data=response.json() print(data) if __name__ == "__main__": run()
Результатом выполнения этого кода будут данные в формате JSON, которые содержат сообщения, посланные в этот бот. Если же сообщений еще нет, то результатом будет пустой список.
'ok': True, 'result': [, 'chat': , 'date': 1578749467, 'text': '/start', 'entities': []>>, , 'chat': , 'date': 1578749481, 'text': 'test'>>]>
Создаем связь с Google-календарем
Теперь перейдем в Google-календарь по следующей ссылке и активируем Google Calendar API .

Загружаем файл credential.json и сохраняем его в том же каталоге, что и наш файл main.py . А далее для установки нужных нам модулей выполняем в терминале следующую команду:
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
После этого скопируем файл quickstart.py , переименуем его в scheduler.py и переместим его в тот же каталог, где уже находятся наши рабочие файлы. Таким образом иерархия файлов будет иметь следующий вид:
Telegram-Bot | |----- main.py |----- scheduler.py |----- credentials.json
После этого нам нужно создать в файле scheduler.py функцию, создающую событие и возвращающую значения булевого типа: True , если событие удалось успешно занести в календарь, и False в противном случае.
from __future__ import print_function import datetime import pickle import os.path from googleapiclient.discovery import build from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request # If modifying these scopes, delete the file token.pickle. # SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] SCOPES = ['https://www.googleapis.com/auth/calendar'] def book_timeslot(event_description,booking_time,input_email): """Shows basic usage of the Google Calendar API. Prints the start and name of the next 10 events on the user's calendar. """ creds = None # The file token.pickle stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.pickle'): with open('token.pickle', 'rb') as token: creds = pickle.load(token) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.pickle', 'wb') as token: pickle.dump(creds, token) service = build('calendar', 'v3', credentials=creds) #--------------------- Manipulating Booking Time ---------------------------- start_time=str(datetime.datetime.now())[:10]+'T'+booking_time+':00+08:00' end_time=str(datetime.datetime.now())[:10]+'T'+str(int(booking_time[:2])+1)+':00:00+08:00' #---------------------------------------------------------------------------- # Call the Calendar API now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time print('Booking a time slot. ') events_result = service.events().list(calendarId='primary', timeMin=now, maxResults=10, singleEvents=True, orderBy='startTime').execute() events = events_result.get('items', []) if not events: event = < 'summary': 'Hair Cut Appointment', 'location': 'Singapore', 'description': str(event_description) + 'with AutomationFeed', 'start': < 'dateTime': start_time, 'timeZone': 'Asia/Singapore', >, 'end': < 'dateTime': end_time, 'timeZone': 'Asia/Singapore', >, 'recurrence': [ 'RRULE:FREQ=DAILY;COUNT=1' ], 'attendees': [ , , ], 'reminders': < 'useDefault': False, 'overrides': [ , , ], >, > event = service.events().insert(calendarId='primary', body=event).execute() print ('Event created: %s' % (event.get('htmlLink'))) return True else: # --------------------- Check if there are any similar start time --------------------- for event in events: start = event['start'].get('dateTime', event['start'].get('date')) if start==start_time: print('Already book. ') return False # -------------------- Break out of for loop if there are no apppointment that has the same time ---------- event = < 'summary': 'Hair Cut Appointment', 'location': 'Singapore', 'description': str(event_description) + 'with AutomationFeed', 'start': < 'dateTime': start_time, 'timeZone': 'Asia/Singapore', >, 'end': < 'dateTime': end_time, 'timeZone': 'Asia/Singapore', >, 'recurrence': [ 'RRULE:FREQ=DAILY;COUNT=1' ], 'attendees': [ , , ], 'reminders': < 'useDefault': False, 'overrides': [ , , ], >, > event = service.events().insert(calendarId='primary', body=event).execute() print ('Event created: %s' % (event.get('htmlLink'))) return True if __name__ == '__main__': input_email='test@gmail.com' booking_time='14:00' result=book_timeslot('Dye',booking_time,input_email)
В этом коде некоторые операторы if изменяют результат в зависимости от текущего времени. Например, если текущее время 07:15, то на встроенной клавиатуре будут отображаться временные интервалы от 08:00 до 18:00.

Затем нам нужно создать функцию, которая будет запрашивать адрес электронной почты пользователя, а также проверять его с помощью регулярных выражений.
def check_email(email): regex = '^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w)+$' if(re.search(regex,email)): print("Valid Email") return True else: print("Invalid Email") return False
Вот так это будет выглядеть в Телеграм.

И теперь нам нужно убедиться, что событие было создано в Календаре Google. Для этого перейдем в Календарь и убедимся, что данное мероприятие существует. Вы можете настроить продолжительность мероприятия, сделать его описание и указать состав участников.