Для того, чтобы научить telegram бота отправлять сообщения о событиях из google calendar (добавлять новые, редактировать старые, следить за обновлениями и т.д.) необходимо связать его с календарём, который мы хотим отслеживать.
В одной из прошлых статей мы создали бота на python с использованием библиотеки telepot, теперь научим его общаться с Google Calendar Api.
Подготовка:
На официальном сайте google находим раздел с описанием условий, необходимых для установки python библиотеки google-api-python-client. Кстати, там же можно найти мануал для других языков программирования. Так как документация постоянно обновляется, вполне вероятно, что у вас будет уже модифицированная версия описания, но на момент написания статьи условия такие:
- Python2.6 и выше
- Установленный pip для python
- Доступ в интернет и любой веб-браузер
- Аккаунт в google
Подключение Google API:
Если все перечисленное в наличии - можно приступать. Включаем Calendar API в консоли вашего google аккаунта по ссылке.
Выбираем "Создать проект" и нажимаем "Продолжить":
Затем "Создать учетные данные":
Дальше гугл в своем мануале рекомендует нажать "Отмена" на экране "Добавление учетных данных" и вместо этого перейти на вкладку "Окно запроса доступа OAuth". Кто мы такие чтобы спорить с разработчиком? И все же поспорим :) Здесь наши пути с мануалом разойдутся, потому что там написано как запускать авторизацию через запрос у пользователя данных о его учетной записи Google. Это когда в интернете какое-то приложение просит разрешить использовать данные вашего аккаунта, вы наверняка не раз встречали такое.
В нашем случае такая авторизация не подходит, так как во-первых, авторизовываться будет бот, а не человек и во-вторых, код бота у нас будет работать на сервере, где и браузера то может не быть чтобы в нем всплыло окошко с просьбой авторизоваться.
Поэтому мы пойдем своим путем. Шаг с добавлением учетных данных не игнорируем. Выбираем что вызов будет происходить с веб-сервера, обращаться мы будем к данным приложения и сервис Google App Engine мы не используем. После этого нажимаем "Выбрать тип учетных данных":
Далее создаем сервисный аккаунт. Это как раз то, что нам нужно для того чтобы к календарю подключался бот, а не человек. Задаем название аккаунта и выбираем для него роль "Администратор App Engine":
Ставим галку напротив пункта "Создать новый закрытый ключ", выбираем тип ключа "Json" и жмем "Создать":
Произойдет генерация и скачивание файла с закрытым ключом.
Если открыть и посмотреть что внутри скачанного json файла, то увидим авторизационные данные:
{
"type": "service_account",
"project_id": "glвп-seавпвап1217",
"private_key_id": "8выаывп7e58ebefавпавп9842470ff2828d8",
"private_key": "-----BEGIN PRIVATE KEY-----тут длинный ключ=\n-----END PRIVATE KEY-----\n",
"client_email": "rer@glassываываenceвыавыа1217.iam.gserviceaccount.com",
"client_id": "105ывавыар0222224603",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/rer%40glываывапр217.iam.gserviceaccount.com"
}
Последним шагом переименовываем файл в более удобное название client_secret.json и переносим его в папку где лежит (или будет лежать) наш бот.
С настройкой Google API все.
Подключение библиотек Python:
Для того, чтобы наш бот на Python смог работать с календарем, потребуется установить две библиотеки.
1. google-api-python-client. Это библиотека Google для взаимодействия календаря и python. Ставится через команду:
pip install --upgrade google-api-python-client
Если у вас стоит несколько разных версий python, не забудьте указать версию pip под которым будет выполняться установка. В случае успеха вы увидите что-то вроде этого:
2. shedule. Эта библиотека позволит нашему python боту через заданные промежутки проверять Google Calendar и отправлять сообщения в telegram. Описание модуля можно посмотреть здесь. Ставится командой:
pip install schedule
При успешной установке на экране будет примерно то же, что мы видели в п.1 :)
Пишем telegram бота на Python, проверяющего Google Calendar и информирующего пользователей по событиям на ближайшие сутки.
На странице с описанием Calendar API есть код python, на котором Google предлагает выполнить проверку того, что все работает корректно. Не будем изобретать велосипед, возьмем этот код за основу и доработаем под наши нужды.
Во-первых, создадим конфиг файл config.py в который положим токен нашего бота (см.предыдущую статью) и путь к Json файлу с ключом, который мы скачали выше.
#Это конфиг файл config.py с данными для интеграционного взаимодейстия
# -*- coding: utf-8-*-
TOKEN = 'код вашего токена в telegram, полученный от botfather'
client_secret_calendar='/root/bot/cal_py/client_secret.json' #указываем путь к скачанному Json
Дальше импортируем конфиг и библиотеки time, telepot, shedule. Из проверочного кода google так же оставляем несколько библиотек. Остальные удаляем.
from __future__ import print_function
import httplib2
import datetime
import time
import config
import telepot
import schedule
from apiclient import discovery
from oauth2client.service_account import ServiceAccountCredentials
Полностью удаляем функцию get_credentials(). В коде google она служит для того, чтобы запрашивать авторизационные данные у пользователя, мы же будем напрямую обращаться к Json файлу. Поэтому в функции main() переменная credentials перестанет выглядеть как credentials = get_credentials(), а модернизируется до credentials = ServiceAccountCredentials.from_json_keyfile_name(config.client_secret_calendar, 'https://www.googleapis.com/auth/calendar.readonly')
Так как мы будем следить за событиями на ближайшие сутки, вычисляем даты "от" и "до" за которые будут подбираться события из календаря:
now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
now_1day = round(time.time())+86400 #плюс сутки
now_1day = datetime.datetime.fromtimestamp(now_1day).isoformat() + 'Z'
Дальше задаем параметры запроса к календарю. Указываем id вашего google календаря, даты за которые будем смотреть события, максимальное количество выводимых результатов и так далее. Полный перечень возможных параметров можно посмотреть здесь.
eventsResult = service.events().list(
calendarId='id google календаря который вы хотите отслеживать', timeMin=now, timeMax=now_1day, maxResults=100, singleEvents=True,
orderBy='startTime').execute()
events = eventsResult.get('items', [])
Потом указываем что именно нужно взять из ответа Google Calendar (заголовок события, текст, дату, ссылку на календарь и т.д. полный перечень возможных параметров можно посмотреть здесь). Записываем полученные данные в сообщение и отправляем его в telegram с помощью sendMessage:
if not events:
print('нет событий на ближайшие сутки')
bot.sendMessage(сюда нужно подставить идентификатор вашего чата telegram, 'нет событий на ближайшие сутки')
else:
msg = '<b>События на ближайшие сутки:</b>\n'
for event in events:
start = event['start'].get('dateTime', event['start'].get('date'))
print(start,' ', event['summary'])
if not event['description']:
print('нет описания')
ev_desc = 'нет описания'
else:
print(event['description'])
ev_desc = event['description']
ev_title = event['summary']
cal_link = '<a href="/%s">Подробнее...</a>'%event['htmlLink']
ev_start = event['start'].get('dateTime')
print (cal_link)
msg = msg+'%s\n%s\n%s\n%s\n\n'%(ev_title, ev_start, ev_desc, cal_link)
print('===================================================================')
bot.sendMessage(сюда нужно подставить идентификатор вашего чата telegram, msg, parse_mode='HTML')
Оборачиваем все что получилось в функцию job() и вызываем её по расписанию с помощью функций библиотеки shedule. Итоговый код:
from __future__ import print_function
import httplib2
import datetime
import time
import config
import telepot
import schedule
from apiclient import discovery
from oauth2client.service_account import ServiceAccountCredentials
def job():
print("I'm working...")
bot = telepot.Bot(config.TOKEN)
def main():
credentials = ServiceAccountCredentials.from_json_keyfile_name(config.client_secret_calendar, 'https://www.googleapis.com/auth/calendar.readonly')
http = credentials.authorize(httplib2.Http())
service = discovery.build('calendar', 'v3', http=http)
now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
now_1day = round(time.time())+86400 #плюс сутки
now_1day = datetime.datetime.fromtimestamp(now_1day).isoformat() + 'Z'
print('Берем 100 событий')
eventsResult = service.events().list(
calendarId=Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.', timeMin=now, timeMax=now_1day, maxResults=100, singleEvents=True,
orderBy='startTime').execute()
events = eventsResult.get('items', [])
if not events:
print('нет событий на ближайшие сутки')
bot.sendMessage(сюда нужно подставить идентификатор вашего чата telegram, 'нет событий на ближайшие сутки')
else:
msg = '<b>События на ближайшие сутки:</b>\n'
for event in events:
start = event['start'].get('dateTime', event['start'].get('date'))
print(start,' ', event['summary'])
if not event['description']:
print('нет описания')
ev_desc = 'нет описания'
else:
print(event['description'])
ev_desc = event['description']
ev_title = event['summary']
cal_link = '<a href="/%s">Подробнее...</a>'%event['htmlLink']
ev_start = event['start'].get('dateTime')
print (cal_link)
msg = msg+'%s\n%s\n%s\n%s\n\n'%(ev_title, ev_start, ev_desc, cal_link)
print('===================================================================')
bot.sendMessage(сюда нужно подставить идентификатор вашего чата telegram, msg, parse_mode='HTML')
if __name__ == '__main__':
main()
print('Listening ...')
#schedule.every(1).minutes.do(job)
#schedule.every().hour.do(job)
schedule.every().day.at("11:15").do(job)
#schedule.every().monday.do(job)
#schedule.every().wednesday.at("13:15").do(job)
while True:
schedule.run_pending()
time.sleep(1)
Запускаем и получаем процесс, по которому каждый день в 11:15 вызывается код, обращающийся к Google calendar, проверяющий какие события произойдут в ближайшие сутки, собирающий эти события в сообщение telegram и отправляющий его в нужный чат.