Команды с косой чертой

Пользовательская команда с косой чертой позволяет пользователям вводить /что-то в поле сообщения, чтобы вызвать ваш сервис. Antimatter отправляет команду на ваш URL и отображает ваш ответ — либо только для этого пользователя, либо для всего канала.

Как работает команда с косой чертой

  1. Пользователь вводит /weather Paris и отправляет. Текст не публикуется.
  2. Antimatter отправляет HTTP-запрос на URL команды, включая данные о том, кто ввёл команду, где и какой текст следует после ключевого слова.
  3. Ваш сервис отвечает в пределах тайм-аута запроса (по умолчанию 30 секунд) сообщением.
  4. Antimatter отображает ответ: только для этого пользователя (эфемерный) или в канале для всех.

Команды принадлежат сообществу, и ключевое слово уникально в пределах сообщества. Встроенные команды, такие как /join, /msg или /away, нельзя заменить. Приложения (плагины) также могут регистрировать команды; см. Серверная часть.

Создание команды

Пользовательские команды с косой чертой включены по умолчанию (Включить пользовательские быстрые команды в Системная консоль › Интеграции › Управление интеграцией, ServiceSettings.EnableCommands). Администраторы сообществ и системные администраторы могут создавать их по умолчанию.

  1. Откройте свой аватар в правом верхнем углу, затем Интеграции › Слэш-команды, затем Добавить быструю команду.
  2. Заполните Заголовок и Описание (отображаются на страницах интеграций).
  3. Введите Ключевое слово, без косой черты и без пробелов, например weather.
  4. Введите URL запроса и выберите Метод запроса: POST (по умолчанию) или GET.
  5. При необходимости задайте Имя пользователя для ответа и Значок ответа. Они используются только в том случае, если сервер позволяет интеграциям заменять имена и значки (см. Имя и значок).
  6. Отметьте Автодополнение, чтобы команда отображалась в списке, когда пользователи вводят /, с Подсказкой для автодополнения (её аргументами, например [city]) и Описанием для автодополнения.
  7. Выберите Сохранить и скопируйте отображённый токен. Ваш сервис использует его для проверки того, что запросы исходят от вашего сервера.

Через API: POST /api/v4/commands с параметрами {"team_id", "trigger", "url", "method": "P", "display_name", "description", "auto_complete": true, "auto_complete_hint", "auto_complete_desc", "username", "icon_url"}. Значение P означает POST, а G — GET. Запрос PUT /api/v4/commands/{command_id}/regen_token выдаёт новый токен.

Запрос, который получает ваш сервис

Команда POST отправляет тело запроса в формате формы (application/x-www-form-urlencoded); команда GET передаёт те же поля в строке запроса. Токен также находится в заголовке Authorization: Token <token>.

ПолеЗначение
tokenТокен команды. Проверяйте его при каждом запросе.
commandТриггер с косой чертой, например /weather.
textВсё, что следует после триггера, например Paris.
user_id, user_nameКто выполнил команду.
channel_id, channel_nameГде она была выполнена.
team_id, team_domainИдентификатор и URL-имя рабочего пространства.
root_idОбсуждение, если команда была выполнена в поле ответа к обсуждению.
trigger_idПозволяет вашему ответу открыть диалог (см. Диалоги). Действительно только в течение короткого времени.
response_urlURL для отправки дополнительных ответов позже (см. Отложенные ответы).
user_mentions, user_mentions_ids, channel_mentions, channel_mentions_idsЛюди и публичные каналы, упомянутые в тексте, если таковые имеются. Каналы учитываются независимо от того, записаны они как #channel-name или ~channel-name.
Для работы пользовательских команд необходимо установить Адрес сайта на сервере: Antimatter формирует response_url на его основе.

Ответ

Ответьте 200 с JSON (Content-Type: application/json):

{
  "response_type": "in_channel",
  "text": "Paris: 18 °C, light rain",
  "attachments": []
}
ПолеЗначение
response_typeephemeral (по умолчанию): ответ видит только тот, кто выполнил команду, и он не сохраняется после перезагрузки. in_channel: ответ публикуется в канале.
text, attachmentsСообщение, как для вебхуков: текст в формате Markdown и вложения, включая кнопки и меню.
username, icon_urlИмя и изображение для отображения, если разрешены переопределения. Настройки самой команды имеют приоритет над этими значениями.
channel_idОпубликовать ответ в другом канале, участником которого должен быть пользователь.
goto_locationURL для открытия после выполнения команды.
props, typeДополнительные свойства и пользовательский тип сообщения, как для вебхуков.
extra_responsesДополнительные ответы, каждый с теми же полями, публикуемые после первого.
skip_slack_parsingtrue сохраняет текст как есть, без преобразования ссылок и упоминаний в стиле Slack.

Ответ, не являющийся JSON, отображается как временное сообщение с телом ответа в качестве текста. 204 No Content ничего не отображает. Любой статус вне диапазона 200–299 показывает пользователю ошибку.

Пример сервиса

Минимальный сервис команды на Python, использующий только стандартную библиотеку:

import hmac
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs

TOKEN = "the token shown when you saved the command"

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        body = self.rfile.read(int(self.headers["Content-Length"])).decode()
        form = {key: values[0] for key, values in parse_qs(body).items()}
        if not hmac.compare_digest(form.get("token", ""), TOKEN):
            self.send_response(401)
            self.end_headers()
            return
        answer = {
            "response_type": "ephemeral",
            "text": f"Hello @{form['user_name']}, you asked for: {form.get('text', '')}",
        }
        data = json.dumps(answer).encode()
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(data)

HTTPServer(("0.0.0.0", 8080), Handler).serve_forever()

Если служба работает по адресу в частной сети, системный администратор должен разрешить её в Разрешить недоверенные внутренние соединения для (ServiceSettings.AllowedUntrustedInternalConnections).

Отложенные ответы

Для задач, которые выполняются дольше, чем время ожидания, сразу отправьте ответ (например, временное сообщение «Работаю над этим…»), а затем отправьте реальный ответ методом POST на response_url. Он принимает тот же JSON, что и обычный ответ, и может быть использован до 5 раз в течение 30 минут после выполнения команды.

curl -X POST "$RESPONSE_URL" -H 'Content-Type: application/json' \
  -d '{"response_type": "in_channel", "text": "Report ready: https://reports.example.com/42"}'

Выполнение команды через API

Скрипты и боты могут выполнять любую команду, встроенную или пользовательскую, как если бы они ввели её вручную:

curl -X POST https://chat.example.com/api/v4/commands/execute \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"channel_id": "'$CHANNEL_ID'", "command": "/weather Paris"}'

GET /api/v4/teams/{team_id}/commands/autocomplete возвращает список команд, которые пользователи могут ввести с автодополнением в сообществе.

Автодополнение

Команды, созданные на страницах интеграций, автодополняются с их триггером, подсказкой и описанием. Команды, зарегистрированные приложениями, могут подробно описывать свои подкоманды и аргументы с помощью AutocompleteData, начиная с model.NewAutocompleteData(trigger, hint, helpText):

  • AddCommand(sub) добавляет подкоманду, которая сама является AutocompleteData.
  • AddTextArgument(helpText, hint, pattern) добавляет аргумент свободного текста.
  • AddStaticListArgument(helpText, required, items) предлагает фиксированный список AutocompleteListItem{Item, Hint, HelpText}.
  • AddDynamicListArgument(helpText, url, required) запрашивает у вашего приложения предложения по мере ввода текста. URL — это маршрут вашего приложения, например /plugins/com.example.weather/cities. Он получает данные о пользователе, канале и сообществе и возвращает JSON-список {"Item", "Hint", "HelpText"}.

Варианты Named… (AddNamedTextArgument и другие) добавляют флаги вида --name value. Оба веб-интерфейса отображают эти подсказки.

Пока кто-то вводит команду, Fusion отображает команду и каждый из её аргументов в виде блока, при этом вводимый аргумент подсвечивается вместе с текстом справки. Аргументы берутся из AutocompleteData или, если его нет, из подсказки: в подсказке вида @[username]... #[channel] слова, начинающиеся с @, относятся к аргументу «люди», а слова, начинающиеся с #, — к аргументу «каналы», вне зависимости от их порядка; ... означает, что аргумент повторяется, а последний аргумент принимает остальной текст.

Каналы в аргументах

В аргументах команды @ предлагает людей, # предлагает каналы и дополняет их в виде #channel-name, а ~ — в виде ~channel-name. Веб-интерфейс и мобильное приложение Antimatter пишут ссылки на каналы с #, поэтому команда, принимающая канал, должна поддерживать обе формы: встроенные /join, /mute и /invite это делают, а их подсказки содержат #[channel].