Пример разработки бота
В этом разделе мы приводим пример разработки бота с автоответом и согласованием. Также Вы можете скачать готового бота и развернуть его на heroku. Информация будет полезна разработчикам приложений.
Создайте страницу с HTTPS-адресом на своем сайте, например, https://example.com/autoresponse. Эта страница-обработчик будет получать запросы от Pyrus-бота. В обработчик добавьте код по следующей схеме.
Проверяем подпись. Подпись гарантирует, что вызов пришел действительно от Pyrus. Вычисляем подпись тела запроса:
python:
def _is_signature_correct(message, secret, signature): secret = str.encode(secret) digest = hmac.new(secret, msg=message, digestmod=hashlib.sha1).hexdigest() return hmac.compare_digest(digest, signature.lower())
php:
strtoupper(hash_hmac("sha1", $response_body_as_string, $security_key))
ruby:
OpenSSL::HMAC.hexdigest('sha1', security_key, response_body_as_string).upcase
С#:
public static bool IsSignatureCorrect(string msg, string sig, string secret) { if (msg is null) throw new ArgumentNullException(nameof(msg)); if (secret is null) throw new ArgumentNullException(nameof(secret)); byte[] hashValue; using (var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(secret))) { hashValue = hmac.ComputeHash(Encoding.UTF8.GetBytes(msg)); } return ToHexString(hashValue) == sig; } private static string ToHexString(IReadOnlyList<byte> hash) { if (hash == null) throw new ArgumentNullException(nameof(hash)); var chArrayLength = hash.Count * 2; var chArray = new char[chArrayLength]; for (int i = 0, index = 0; i < chArrayLength; i += 2, index++) { var b = hash[index]; chArray[i] = GetHexValue(b / 16); chArray[i + 1] = GetHexValue(b % 16); } return new string(chArray); } private static char GetHexValue(int i) { return i < 10 ? (char)('0' + i) : (char)('A' + i - 10); }
Эти функции производят конвертацию запроса в виде строк в byte array с использованием UTF и вычисляют HMAC-дайджест с использованием алгоритма SHA1 для хеширования.
Сравниваем со значением заголовка X-Pyrus-Sig, чтобы удостовериться, что запрос действительно поступил от Pyrus. Если заголовки не совпадают, выполнение останавливаем.
Выбираем значение author.id из полученного объекта task (см. полное описание в разделе Задача по форме с комментариями):
{ "id": 5600, "text": "New task", "create_date": "2016-12-02T11:20:22Z", "last_modified_date": "2016-12-02T11:20:22Z", "parent_task_id": 0, "author": { "id": 1731, "first_name": "tester", "last_name": "papirus", "email": "test@pyrus.com" }, "approvals": [[{ "person": { "id": 21913, "first_name": "bot", "last_name": "papirus", "email": "bot@pyrus.com" }, "approval_choice": "waiting" }], [{ "person": { "id": 1731, "first_name": "tester", "last_name": "papirus", "email": "test@pyrus.com" }, "approval_choice": "waiting" }]], "comments": [{ "create_date": "2016-12-02T11:20:22Z", "author": { "id": 1731, "first_name": "tester", "last_name": "papirus", "email": "test@pyrus.com" }, "approvals_added": [{ "person": { "id": 21913, "first_name": "bot", "last_name": "papirus", "email": "bot@pyrus.com" }, "step": 1 }, { "person": { "id": 1731, "first_name": "tester", "last_name": "papirus", "email": "test@pyrus.com" }, "step": 2 }], "id": 12208 }] }
В примере выше author.email = test@pyrus.com.
Формируем тело ответа:
{ "text": "Hello, test@pyrus.com. This task approved by bot.", "approval_choice": "approved" }
В этом примере:
- text (необязательный параметр) — текст комментария. Если пропущен, бот сделает комментарий без текста;
- approval_choice — установка согласования бота. Если согласование не требуется, этот параметр будет проигнорирован сервером. Если бот работает с формой, то этот параметр обязательный;
Возвращаем ответ HTTP 200 ОК и тело, как указано выше.
Приведем полный пример с кодом бота на Python.
import hmac import hashlib import json from flask import Flask from flask import request app = Flask(__name__) @app.route("/", methods=['GET', 'POST']) def index(): body = request.data signature = request.headers['x-pyrus-sig'] secret = 'This-is-bot-secret-key-VtBOEesdOnIcqGaWQeFkWFqyzgdt2PGsZVWBc8h8H0-xU9ux-dN37IjcAqf2pzeqoo5FqdtoH' return _prepare_response(body.decode('utf-8')) def _prepare_response(body): task = json.loads(body)["task"] task_author = task["author"]["email"] return "{{\"text\": \"Hello, {}. This task approved by bot.\", \"approval_choice\": \"approved\"}}".format(task_author) if __name__ == "__main__": app.run("127.0.0.1", 5001) # !!!Не забудьте заменить адрес!!!
Теперь добавьте нового бота и в поле URL впишите адрес обработчика (в нашем примере это https://example.com/autoresponse).
Для проверки поставьте в Pyrus задачу на бота с запросом его согласования. Убедитесь, что в задаче получен ответ с текстом Approved by bot и стоит согласование бота.