WeChat — это китайское многофункциональное приложение для мгновенного обмена сообщениями, социальных сетей и мобильной оплаты, созданное компанией Tencent. Оно было выпущено впервые в 2011 году, а к 2018 году стало одним из крупнейших самостоятельных мобильных приложений по количеству ежемесячно активных пользователей, с более чем 1 миллиардом ежемесячно активных пользователей (902 миллиона ежедневно активных пользователей). (Согласно википедии)
Gem WeChat помогает разработчикам Rails легко интегрировать платформу официальных аккаунтов WeChat или микросайта WeChat, включая следующие возможности:- API отправки сообщений (send message) (можно использовать как через консоль, так и через сервер Rails)
wechat
использует ту же самую API в консоли, поэтому вы можете быстро взаимодействовать с сервером WeChat без запуска среды веб-кода.DSL-шаблон отклика может использоваться в контроллере Rails, что позволяет использовать событийно-ориентированное интерфейс для обработки сообщений, отправленных конечными пользователями. Если ваше приложение требует WeChat OAuth 2.0, рекомендуется использовать omniauth-wechat-oauth2 для применения devise аутентификации.
Если в проекте используется стиль UI от Tencent weui, доступен гем weui-rails.
Для веб-страниц с приложением WeChat, пожалуйста, используйте wechat_api
, которое содержит только веб-функциональность, в отличие от традиционного типа сообщений wechat_responder
.
Существует более полная демонстрация wechat-starter, которая дополнительно включает функцию платежного SDK.
Используйте gem install
gem install "wechat"
# Если версия Ruby меньше 2.6
# gem install wechat -v 0.12.4
Или добавьте его в ваш Gemfile:
gem 'wechat'
# Если версия Rails меньше 6.0
# gem 'wechat', '~> 0.12.4'
Запустите следующую команду для установки:
bundle install
Запустите генератор:
rails generate wechat:install
```Команда `rails g wechat:install` создаёт начальный конфигурационный файл `wechat.yml`, который включает пример контроллера WeChat и соответствующие маршруты.Активируйте запись сессий:
```console
rails g wechat:session
rake db:migrate
Активация записи сессий создаст два файла в папке Rails; вы можете добавить дополнительные столбцы в таблицу wechat_session
и объявить связь с таблицей пользователей. Также можно хранить данные непосредственно в hash_store. Если вы используете PostgreSQL, использование hstore/json может быть лучше, но лучшим способом является добавление специального столбца для записи данных (способ Rails).
Использование Redis для хранения токена и билета WeChat:
rails g wechat:redis_store
Хранение Redis поддерживает приложения Rails, работающие на нескольких серверах. Рекомендуется использовать файловое хранилище по умолчанию, если используется один сервер. Кроме того, команда wechat
не будет читать токены/билеты, хранящиеся в Redis.
Активировать базу данных для конфигураций WeChat:
rails g wechat:config
rake db:migrate
После выполнения миграции будет создана таблица wechat_configs
, которая позволяет хранить несколько аккаунтов WeChat. ## Конфигурация
Убедитесь, что завершены все настройки с серверной части на основе Ruby on Rails, затем отправьте эти настройки на сайт управления WeChat от компании Tencent. В противном случае, WeChat выдаст ошибку.
Адрес URL, созданный выполнением команды rails g wechat:install
, будет иметь вид http://ваш_сервер.com/wechat
.Для настройки appid/corpid и секрета см. ниже раздел.
Убедитесь, что атрибуты record
содержат access_token
, token_expires_in
, got_token_at
.
def client
@client ||= Wechat::Api.new(app_id, app_secret, token_file, network_setting, jsapi_ticket_file, record)
end
Чтобы использовать автономную команду wechat
, вам потребуется создать конфигурационный файл ~/.wechat.yml
и включить следующий контент для публичного аккаунта. Атрибут access_token
будет записываться в файл /var/tmp/wechat_access_token
.
appid: "my_appid"
secret: "my_secret"
access_token: "/var/tmp/wechat_access_token"
Для корпоративного аккаунта следует использовать corpid
вместо appid
, так как корпоративный аккаунт поддерживает несколько приложений (которые Tencent называет агентами) в одном аккаунте. Получение corpsecret
немного сложнее — его необходимо создать в режиме управления -> настройках привилегий и создать любую группу управления для получения доступа. Учитывая, что Tencent предоставляет китайский интерфейс для своей консоли управления, настоятельно рекомендуется найти коллегу, который знает мандаринский китайский язык, чтобы помочь вам получить corpsecret
.
Пользователям Windows требуется хранить .wechat.yml
в директории C:\Users\[имя пользователя]
(замените имя пользователя на ваше), также обратите внимание на направление разделителя каталога.```
corpid: "my_appid"
corpsecret: "my_secret"
agentid: 1 # целое число, которое можно получить из настроек приложения
access_token: "C:/Users/[имя пользователя]/wechat_access_token"
### Настройка для Ruby on Rails
Файл конфигурации Ruby on Rails поддерживает различные окружения аналогично файлу `database.yml`. После выполнения команды `rails generate wechat:install` вы можете найти файл конфигурации в директории `config/wechat.yml`.
Пример конфигурации для публичного аккаунта:
default: &default appid: "app_id" secret: "app_secret" token: "app_token" access_token: "/var/tmp/wechat_access_token" jsapi_ticket: "/var/tmp/wechat_jsapi_ticket"
production:
appid: <%= ENV['WECHAT_APPID'] %>
secret: <%= ENV['WECHAT_APP_SECRET'] %>
token: <%= ENV['WECHAT_TOKEN'] %>
access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %>
jsapi_ticket: <%= ENV['WECHAT_JSAPI_TICKET'] %>
oauth2_cookie_duration: <%= ENV['WECHAT_OAUTH2_COOKIE_DURATION'] %> # секунды
development:
<<: *default
trusted_domain_fullname: "http://your_dev.proxy.qqbrowser.cc"
test:
<<: *default
Хотя это опционально для публичного аккаунта, но настоятельно рекомендуется включить режим шифрования, добавив следующие два элемента в файл wechat.yml
.
default: &default
encrypt_mode: true
encoding_aes_key: "my_encoding_aes_key"
Аккаунты корпоративного типа должны использовать режим шифрования (encrypt_mode: true
активирован по умолчанию, дополнительное конфигурирование не требуется).
Значения token
и encoding_aes_key
можно получить из управления консоли -> одного из приложений агента -> выбор режима, выбрать режим обратного вызова и установить/получить значения.```yaml
default: &default
corpid: "corpid"
corpsecret: "corpsecret"
agentid: 1
access_token: "C:/Users/[user_name]/wechat_access_token"
token: ""
encoding_aes_key: ""
jsapi_ticket: "C:/Users/[user_name]/wechat_jsapi_ticket"
production: corpid: <%= ENV['WECHAT_CORPID'] %> corpsecret: <%= ENV['WECHAT_CORPSECRET'] %> agentid: <%= ENV['WECHAT_AGENTID'] %> access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %> token: <%= ENV['WECHAT_TOKEN'] %> timeout: 30 skip_verify_ssl: true # не рекомендовано encoding_aes_key: <%= ENV['WECHAT_ENCODING_AES_KEY'] %> jsapi_ticket: <%= ENV['WECHAT_JSAPI_TICKET'] %> oauth2_cookie_duration: <%= ENV['WECHAT_OAUTH2_COOKIE_DURATION'] %>
development: <<: *default trusted_domain_fullname: "http://your_dev.proxy.qqbrowser.cc"
test: <<: *default
Примечания по поддержке нескольких аккаунтов платформы `WeChat Official Accounts` / `WeChat Enterprise` (например, добавление аккаунта `wx2`). Конфигурация для нескольких аккаунтов аналогична конфигурации многобазовых систем в файле `config/database.yml`, где сегменты `development`, `test`, `production` являются базовой конфигурацией, а для добавления дополнительного аккаунта с названием `wx2` требуется добавление `wx2_development`, `wx2_test`, `wx2_production`.
Объявление дополнительного `wechat_responder`:
```ruby
wechat_responder account: :wx2
Используйте Wechat.api
или Wechat.api(:default)
, чтобы представить основной API WeChat. Используйте Wechat.api(:wx2)
, чтобы вызвать API WeChat для аккаунта wx2
.
Wechat command line
) можно переключиться на другой аккаунт WeChat, добавив опциональные параметры -a ACCOUNT [--account=ACCOUNT]
.Для получения подробностей о поддержке нескольких аккаунтов, пожалуйста, проверьте PR 150.
Для мини-программы WeChat можно указать элементом type
:
# Аккаунты мини-программ
mini_development:
<<: *default
appid: "my_appid"
secret: "my_secret"
# `mp` — это сокращение от **mini program** (мини-программа)
type: 'mp'
После активации конфигурации аккаунта в базе данных будет создана следующая таблица:Атрибут | Тип | Примечание |
---|---|---|
environment | string | Обязательное поле. Окружение конфигурации аккаунта. Типичные значения: production , development и test . Например, конфигурация production будет доступна только в окружении production . По умолчанию равно development . |
account | string | Обязательное поле. Уникальное имя аккаунта WeChat. Имена аккаунтов должны быть уникальными в каждом окружении. |
enabled | boolean | Обязательное поле. Отображает активирован ли этот аккаунт. По умолчанию равно true . |
appid | string | ID публичного аккаунта. Либо это поле, либо corpid должно быть указано. |
secret | string | Настройки публичного аккаунта. Обязательное поле при наличии поля appid . |
corpid | string | ID корпоративного аккаунта. Либо это поле, либо appid должно быть указано. |
corpsecret | string | Настройки корпоративного аккаунта. Обязательное поле при наличии поля corpid . |
agentid | integer | Настройки корпоративного аккаунта. Обязательное поле при наличии поля corpid . |
encrypt_mode | boolean | |
encoding_aes_key | string | Обязательное поле при значении encrypt_mode равном true . |
token | string | Обязательное поле. |
access_token | string | Обязательное поле. Путь к файлу хранения access token . |
jsapi_ticket | string | Обязательное поле. Путь к файлу хранения jsapi ticket . |
skip_verify_ssl | boolean | |
timeout | integer | По умолчанию равно 20. |
trusted_domain_fullname | string | После обновления конфигураций аккаунтов базы данных вам потребуется перезапустить сервер или вызвать Wechat.reload_config! для перезагрузки обновлений.##### Настройка приоритета |
Выполнение команды wechat
в корневой папке приложения Rails будет использовать конфигурацию Rails в первую очередь (default
раздел). Если она не найдена, будет использоваться ~/.wechat.yml
. Такое поведение позволяет управлять большим количеством аккаунтов WeChat для бизнеса и публичных аккаунтов без изменения домашнего файла ~/.wechat.yml
.
Когда активирована конфигурация аккаунта базы данных, конфигурации базы данных будут загружены после файла конфигурации .yml
или параметров окружения. Когда конфигурации с одинаковым именем аккаунта существуют как в базе данных, так и в файле .yml
или параметрах окружения, конфигурация из базы данных имеет приоритет.
Стабильность сервиса WeChat от Tencent может меняться, поэтому может потребоваться установка большего времени ожидания; значение по умолчанию — 20 секунд, если не указано иначе.
Сертификат SSL также может быть поврежден по какой-то причине в Китае, это сообщено и если это произошло с вами, вы можете установить skip_verify_ssl: true
. (не рекомендовано)
wechat_responder
или wechat_api
.```rubyclass WechatFirstController < ActionController::Base wechat_responder account: :new_account, account_from_request: Proc.new { |request| request.params[:wechat] }
on :text, with: "помощь", respond: "контент помощи" end
Или вы можете предоставить полный список опций.
```ruby
class WechatFirstController < ActionController::Base
wechat_responder appid: "app1", secret: "secret1", token: "token1", access_token: Rails.root.join("tmp/access_token1"),
account_from_request: Proc.new { |request| request.params[:wechat] }
on :text, with: "помощь", respond: "контент помощи"
end
account_from_request
— это Proc
, который принимает параметр request
и возвращает соответствующее имя аккаунта WeChat. В приведённых выше примерах controller
выбирает аккаунт на основе параметра wechat
, переданного в запросе. Если account_from_request
не указан или этот Proc
вернёт nil
, используется конфигурация, указанная параметром account
или полным списком опций.
JS-SDK позволяет контролировать поведение приложения WeChat в HTML путём внедрения конфигурационной подписи. Вспомогательный модуль wechat_config_js
выполняет эту задачу простым способом:
Чтобы сделать wechat_config_js
работоспособным, вам нужно сначала поместить либо wechat_api
, либо wechat_responder
в контроллер.
<body>
<%= wechat_config_js debug: false, api: %w(скрытьМенюЭлементы закрытьОкно) -%>
<script type="application/javascript">
wx.ready(function() {
wx.hideOptionMenu();
});
</script>
<a href="javascript:wx.closeWindow();">Закрыть</a>
</body>
```Настройте `trusted_domain_fullname`, если вы работаете в режиме разработки и ваше приложение запущено за прокси-сервером обратного запроса; в противном случае плагин WeChat не сможет получить правильный URL для последующей подписи.#### Аутентификация OAuth2.0
Для публичного аккаунта следующий код получает информацию о пользователе.
```ruby
class CartController < ActionController::Base
wechat_api
def index
wechat_oauth2 do |openid|
@current_user = User.find_by(wechat_openid: openid)
@articles = @current_user.articles
end
# Укажите account_name для использования произвольной конфигурации аккаунта WeChat
# wechat_oauth2('snsapi_base', nil, account_name) do |openid|
# ...
# end
end
end
Для корпоративного аккаунта следующий код получает информацию о сотруднике предприятия.
class WechatsController < ActionController::Base
layout 'wechat'
wechat_responder
def apply_new
wechat_oauth2 do |userid|
@current_user = User.find_by(wechat_userid: userid)
@apply = Apply.new
@apply.user_id = @current_user.id
end
end
end
Метод wechat_oauth2
уже реализует необходимую логику аутентификации OAuth2.0 и работы с cookies. userid
определяется как UserID сотрудника предприятия, а openid
— как ID пользователя, который подписан на публичный аккаунт. Обратите внимание, что openid
будет различаться для одного и того же пользователя, если он подписан на различные публичные аккаунты.
Примечание:
wechat_responder
в своём контроллере, вы не сможете использовать действия create
и show
в этом контроллере, иначе возникнут ошибки.Доступный API различается между публичным аккаунтом и корпоративным аккаунтом, поэтому мы предоставляем различные наборы команд.
Не беспокойтесь, если вы не можете читать китайский в комментариях, он сохранен там для удобства копирования и поиска в официальной документации.#### Командная строка для публичного аккаунта
$ wechat
WeChat Public Account commands:
wechat addvoicetotranscriptfortext [VOICE_ID] # Подача аудиофайла для распознавания в виде текста через API
wechat callbackip # Получение IP адреса сервера WeChat
wechat clear_quota # Сброс количества вызовов API до нуля
wechat custom_image [OPENID, IMAGE_PATH] # Отправка сообщения с изображением для службы поддержки клиентов
wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # Отправка сообщения с музыкальным треком для службы поддержки клиентов
wechat custom_news [OPENID, NEWS_YAML_PATH] # Отправка сообщения с новостями для службы поддержки клиентов
wechat custom_text [OPENID, TEXT_MESSAGE] # Отправка текстового сообщения для службы поддержки клиентов
wechat custom_video [OPENID, VIDEO_PATH] # Отправка видео сообщения для службы поддержки клиентов
wechat custom_voice [OPENID, VOICE_PATH] # Отправка голосового сообщения для службы поддержки клиентов
wechat customservice_getonlinekflist # Получение информации о текущих онлайн сотрудниках службы поддержки клиентов
wechat group_create [GROUP_NAME] # Создание группы
wechat group_delete [GROUP_ID] # Удаление группы
wechat group_update [GROUP_ID, NEW_GROUP_NAME] # Изменение имени группы
wechat groups # Получение всех групп
wechat material_get [MEDIA_ID, PATH] # Скачивание постоянного медиафайла
``` wechat material_add [MEDIA_TYPE, PATH] # Загрузка постоянного медиафайла
wechat material_add_news [MPNEWS_YAML_PATH] # Загрузка постоянного материала с новостями
wechat material_count # Получение общего количества постоянных материалов
wechat material_delete [MEDIA_ID] # Удаление постоянного материала
wechat material_list [TYPE, OFFSET, COUNT] # Получение списка постоянных материалов
wechat media [MEDIA_ID, PATH] # Скачивание медиафайла
wechat media_hq [MEDIA_ID, PATH] # Скачивание высококачественного аудиофайла
wechat media_create [MEDIA_TYPE, PATH] # Загрузка медиафайла
wechat media_uploadimg [IMAGE_PATH] # Загрузка изображения для сообщения с новостями
wechat media_uploadnews [MPNEWS_YAML_PATH] # Загрузка материала с новостями
wechat menu # Текущее меню
wechat menu_addconditional [CONDITIONAL_MENU_YAML_PATH] # Создание условного меню
wechat menu_create [MENU_YAML_PATH] # Создание меню wechat menu_delconditional [MENU_ID] # Удаление условного меню wechat menu_delete # Удаление меню wechat menu_trymatch [USER_ID] # Тестирование соответствия условного меню wechat message_mass_delete [MSG_ID] # Удаление массового сообщения wechat message_mass_get [MSG_ID] # Получение состояния отправки массового сообщения wechat message_mass_preview [WX_NAME, MPNEWS_MEDIA_ID] # Предварительный просмотр материала с текстовым содержимым
wechat qrcode_create_scene [SCENE_ID_OR_STR, EXPIRE_SECONDS] # Запрос временного QR-кода
wechat qrcode_download [TICKET, QR_CODE_PIC_PATH] # Загрузка QR-кода по тикету
wechat queryrecoresultfortext [VOICE_ID] # API распознавания речи — получение результата распознавания
wechat shorturl [LONG_URL] # Преобразование длинной ссылки в короткую
wechat tag [TAGID] # Получение списка подписчиков по метке
wechat tag_add_user [TAG_ID, OPEN_IDS] # Добавление меток группе пользователей
wechat tag_create [TAGNAME, TAG_ID] # Создание метки
wechat tag_del_user [TAG_ID, OPEN_IDS] # Удаление меток у группы пользователей
wechat tag_delete [TAG_ID] # Удаление метки
wechat tag_update [TAG_ID, TAGNAME] # Обновление имени метки
wechat tags # Получение всех меток
wechat template_message [OPENID, TEMPLATE_YAML_PATH] # Шаблон сообщения
wechat translatecontent [CONTENT] # API перевода — перевод контента
wechat user [OPEN_ID] # Получение базовой информации пользователя
wechat user_batchget [OPEN_ID_LIST] # Получение базовой информации группы пользователей
wechat user_change_group [OPEN_ID, TO_GROUP_ID] # Изменение группы пользователя
wechat user_group [OPEN_ID] # Получение текущей группы пользователя
wechat user_update_remark [OPEN_ID, REMARK] # Обновление примечания пользователя мычэт юзерс # Список подписчиков мычэт wxa_msg_sec_check [КОНТЕНТ] # проверяет, содержит ли текст запрещенный или незаконный контент.
мычэт wxacode_download [WXA_CODE_PIC_PATH, ПУТЬ, ШИРИНА] # скачивает код мини-приложения
мычэт клэр_квота # сброс количества вызовов API до нуля
```#### Команды командной строки для корпоративного аккаунта WeChat
$ мычэт Команды корпоративного аккаунта WeChat: мычэт агэнт [АГЭНТ_ИД] # Получение деталей агента корпоративного аккаунта мычэт агэнт_лист # Получение списка агентов мычэт батч_джоб_резулт [ДЖОБ_ИД] # Получение результата асинхронной задачи мычэт батч_реплейспарти [БАТЧ_ПАРТИ_СВМ_ИД] # Полное замещение отделов мычэт батч_реплейсузер [БАТЧ_ЮЗЕР_СВМ_ИД] # Полное замещение участников мычэт батч_синкюзер [СИНК_ЮЗЕР_СВМ_ИД] # Инкрементальное обновление участников мычэт кэбэкіп # Получение IP адреса сервера WeChat мычэт клэр_квота # Обнуление количества вызовов API мычэт конверт_то_openid [ЮЗЕР_ИД] # Преобразование ЮЗЕР_ИД в OPENID мычэт конверт_то_юзерид [ОПЕНІД] # Преобразование ОПЕНІД в ЮЗЕР_ИД мычэт кастом_имэдж [ОПЕНІД, ИМЭЖ_ПАТХ] # Отправка сообщения с изображением через службу поддержки мычэт кастом_мьюzik [ОПЕНІД, ТХУМБНАЙЛ_ПАТХ, МЬЮZ_URL] # Отправка сообщения с музыкой через службу поддержки мычэт кастом_ньюс [ОПЕНІД, НЬЮС_ЯМЛ_ПАТХ] # Отправка сообщения с новостями через службу поддержки wechat custom_text [OPENID, TEXT_MESSAGE] # Отправка текстового сообщения через службу поддержки wechat custom_video [OPENID, VIDEO_PATH] # Отправка видео сообщения через службу поддержки wechat custom_voice [OPENID, VOICE_PATH] # Отправка голосового сообщения через службу поддержки wechat department [DEPARTMENT_ID] # Получение списка отделов wechat department_create [NAME, PARENT_ID] # Создание нового отдела wechat department_delete [DEPARTMENT_ID] # Удаление отдела wechat department_update [DEPARTMENT_ID, NAME] # Обновление названия отдела wechat getusercumulate [BEGIN_DATE, END_DATE] # Получение данных о накопленных пользователях wechat getusersummary [BEGIN_DATE, END_DATE] # Получение данных о изменениях пользователей wechat invite_user [USER_ID] # Приглашение пользователя присоединиться wechat material [MEDIA_ID, PATH] # Скачивание постоянного медиа контента wechat material_add [MEDIA_TYPE, PATH] # Загрузка постоянного медиа контента wechat material_count # Получение общего количества постоянного медиа контента wechat material_delete [MEDIA_ID] # Удаление постоянного медиа контента wechat material_list [TYPE, OFFSET, COUNT] # Получение списка постоянного медиа контента
wechat media [MEDIA_ID, PATH] # Загрузка медиафайлов
wechat media_create [MEDIA_TYPE, PATH] # Создание медиафайлов
wechat media_hq [MEDIA_ID, PATH] # Загрузка высококачественного аудиофайла
``` wechat media_uploadimg [IMAGE_PATH] # Загрузка изображения для сообщения с картинками
wechat menu # Текущее меню
wechat menu_addconditional [CONDITIONAL_MENU_YAML_PATH] # Создание условного меню
wechat menu_create [MENU_YAML_PATH] # Создание меню
wechat menu_delconditional [MENU_ID] # Удаление условного меню
wechat menu_delete # Удаление меню
wechat menu_trymatch [USER_ID] # Тестирование соответствия условного меню
wechat message_send [OPENID, TEXT_MESSAGE] # Отправка текстового сообщения
wechat qrcode_download [TICKET, QR_CODE_PIC_PATH] # Загрузка QR-кода по тикету
wechat tag [TAG_ID] # Получение членства в метках
wechat tag_add_department [TAG_ID, PARTY_IDS] # Добавление отдела в метку
wechat tag_add_user [TAG_ID, USER_IDS] # Добавление пользователя в метку
wechat tag_create [TAG_NAME, TAG_ID] # Создание метки
wechat tag_del_department [TAG_ID, PARTY_IDS] # Удаление отдела из метки
wechat tag_del_user [TAG_ID, USER_IDS] # Удаление пользователя из метки
wechat tag_delete [TAG_ID] # Удаление метки
wechat tag_update [TAG_ID, TAG_NAME] # Обновление имени метки
wechat tags # Получение всех меток
wechat template_message [OPENID, TEMPLATE_YAML_PATH] # Шаблон сообщения
wechat upload_replaceparty [BATCH_PARTY_CSV_PATH] # Полная замена отделов путём загрузки файла
wechat upload_replaceuser [BATCH_USER_CSV_PATH] # Полная замена пользователей путём загрузки файла wechat user [OPEN_ID] # Получение базовой информации о пользователе
wechat user_batchdelete [USER_ID_LIST] # Блоковое удаление пользователей
wechat user_create [USER_ID, NAME] # Создание пользователя
wechat user_delete [USER_ID] # Удаление пользователя
wechat user_list [DEPARTMENT_ID] # Получение подробной информации о пользователях отдела
wechat user_simplelist [DEPARTMENT_ID] # Получение списка пользователей отдела
мы используем `wechat user_update_remark [OPEN_ID, REMARK]` # Установка заметок```Примечание: `replaceparty` полная загрузка отделов поддерживает только один корневой узел как отдел и не поддерживает параллельные множественные корневые узлы.
### Пример использования командной строки (частично)
#### Получение всех открытых ID пользователей
$ wechat users
{"total"=>4, "count"=>4, "data"=>{"openid"=>["oCfEht9***********", "oCfEhtwqa***********", "oCfEht9oMCqGo***********", "oCfEht_81H5o2***********"]}, "next_openid"=>"oCfEht_81H5o2***********"}
#### Получение информации о пользователе
$ wechat user "oCfEht9***********"
{"subscribe"=>1, "openid"=>"oCfEht9***********", "nickname"=>"Nickname", "sex"=>1, "language"=>"zh_CN", "city"=>"徐汇", "province"=>"上海", "country"=>"中国", "headimgurl"=>"http://wx.qlogo.cn/mmopen/ajNVdqHZLLBd0SG8NjV3UpXZuiaGGPDcaKHebTKiaTyof*********/0", "subscribe_time"=>1395715239}
#### Получение меню
$ wechat menu
{"menu"=>{"button"=>[{"type"=>"view", "name"=>"защищённое", "url"=>"http:///protected", "sub_button"=>[]}, {"type"=>"view", "name"=>"общедоступное", "url"=>"http://", "sub_button"=>[]}]}}
#### Создание меню
Запустите команду `rails g wechat:menu`, чтобы сгенерировать файл определения меню в формате YAML:
type: "scancode_waitmsg"
name: "Привязать QR-код для питания"
key: "BINDING_QR_CODE"
type: "click"
name: "Забронировать обед"
key: "BOOK_LUNCH"
type: "miniprogram"
name: "Пример мини-приложения"
url: "http://ericguo.com/"
appid: "wx1234567890"
pagepath: "pages/index"
type: "click"
name: "Запись входа/выхода"
key: "BADGE_IN_OUT"
type: "click"
name: "Остаток отпуска"
key: "ANNUAL_LEAVE"
type: "view" name: "О нас" url: "http://blog.cloud-mes.com/"
Запустите следующую команду для загрузки меню:
```
$ wechat menu_create menu.yaml
```
Внимание: убедитесь, что у вас есть права управления для этого приложения, в противном случае вы получите ошибку [60011](http://qydev.weixin.qq.com/wiki/index.php?title=全局返回码说明).
#### Отправка пользовательской новости
Отправка пользовательской новости также должна быть определена в виде файла YAML, такого как `articles.yml`.
```
articles:
-
title: "Выступление президента Си Цзиньпина в Европейском университете Брюсселя"
description: "新华网比利时布鲁日 4 月 1 日电 国家主席习近平 1 日在比利时布鲁日欧洲学院发表重要讲话"
url: "http://news.sina.com.cn/c/2014-04-01/232629843387.shtml"
pic_url: "http://i3.sinaimg.cn/dy/c/2014-04-01/1396366518_bYays1.jpg"
```
После этого вы можете выполнить следующую команду:
```
$ wechat custom_news oCfEht9oM*********** articles.yml
```
#### Отправка шаблонного сообщения
Отправка шаблонного сообщения с помощью файла YAML аналогична. Определите `template.yml`, а содержание будет просто шаблонным контентом.
```
template:
template_id: "o64KQ62_xxxxxxxxxxxxxxx-Qz-MlNcRKteq8"
url: "http://weixin.qq.com/download"
topcolor: "#FF0000"
data:
first:
value: "Привет, вы успешно зарегистрировались"
color: "#0A0A0A"
keynote1:
value: "Здоровье бег 5км"
color: "#CCCCCC"
keynote2:
value: "2014-09-16"
color: "#CCCCCC"
keynote3:
value: "Центральный парк,浦东上海"
color: "#CCCCCC"
remark:
value: "Добро пожаловать обратно"
color: "#173177"
```
После этого вы можете выполнить следующую команду:
$ мычат_шаблонное_сообщение oCfEht9oM*********** template.yml
В коде:
```ruby
template = YAML.load(File.read(template_yaml_path))
Wechat.api.шаблонное_сообщение_отправить Wechat::Сообщение.к_получателю(openid).шаблон(template["template"])
Если использовать wechat_api
или wechat_responder
в контроллере, можно также использовать wechat
как сокращение (поддерживает несколько аккаунтов):
template = YAML.load(File.read(template_yaml_path))
wechat.шаблонное_сообщение_отправить Wechat::Сообщение.к_получателю(openid).шаблон(template["template"])
Хотя пользователи всегда могут получить доступ ко всем функциям WeChat через Wechat.api
, но настоятельно рекомендуется использовать wechat
непосредственно в контроллере. Это обязательно требуется, если планируете поддерживать несколько аккаунтов, и помогает отделить логику WeChat от модели.
class WechatReportsController < ApplicationController
wechat_api
layout 'wechat'
def index
@lots = Lot.with_preloading.wip_lot
end
end
Используйте Wechat.api
для доступа к функциям WeChat API в любом месте.
Ниже приведён пример вызова API распознавания голоса через rails console
:
# Аудиофайл с версией ID3 2.4.0, содержит: MPEG ADTS, layer III, v2, 40 kbps, 16 kHz, Mono
test_voice_file='test_voice.mp3'
Wechat.api.добавить_голос_для_распознавания_текста('test_voice_id', File.open(test_voice_file))
Wechat.api.получить_результат_распознавания_текста 'test_voice_id'
Используйте Wechat.дешифровать(зашифрованные_данные, сессионный_ключ, iv)
для декодирования данных. Подробнее в разделе Проверка подписи.## wechat_responder — DSL контроллера ответа для Rails
Чтобы отвечать на сообщение, отправленное пользователем, разработчику Rails необходимо создать контроллер ответа wechat и определить маршруты в routes.rb
.
resources :wechat, only: [:show, :create]
Таким образом, ActionController должен быть определён следующим образом:
class WechatsController < ActionController::Base
wechat_responder
# По умолчанию используется текстовый ответ при отсутствии других совпадений
on :text do |request, content|
request.reply.text "echo: #{content}" # Просто эхо
end
# При получении слова 'help', будет активирован этот ответ
on :text, with: 'help' do |request|
request.reply.text 'help content'
end
# При получении '<n>news', будет сопоставлено и количество новостей будет равно <n>
on :text, with: /^(\d+) news$/ do |request, count|
# В WeChat статьи могут содержать максимум 8 элементов, больше 8 будут удалены.
news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: 'Название новости', content: "Новость №#{n}" } }
request.reply.news(news) do |article, n, index| # article — это объект ответа
article.item title: "#{index}. #{n[:title]}", description: n[:content], pic_url: 'http://www.baidu.com/img/bdlogo.gif', url: 'http://www.baidu.com/'
end
end
on :event, with: 'subscribe' do |request|
request.reply.text "#{request[:FromUserName]} подписался сейчас"
end
end
``` # Когда пользователь отписывается, сканируя QR-code qrscene_xxxxxx для подписки в публичном аккаунте,
# следует отметить, что пользователь одновременно подписывается в публичном аккаунте, поэтому событие подписки больше не будет вызвано.
on :scan, with: 'qrscene_xxxxxx' do |request, ticket|
request.reply.text "Отписавшийся пользователь #{request[:FromUserName]} Билет #{ticket}"
end # Когда пользователь подписывается, сканируя scene_id в публичном аккаунте
on :scan, with: 'scene_id' do |request, ticket|
request.reply.text "Подписавшийся пользователь #{request[:FromUserName]} Билет #{ticket}"
end
# Когда ни один из ответов на события scan не может быть использован для подписавшегося пользователя,
# который сканировал scene_id
on :event, with: 'scan' do |request|
if request[:EventKey].present?
request.reply.text "Событие scan получил EventKey #{request[:EventKey]} Билет #{request[:Ticket]}"
end
end
end
on :scan, with: 'BINDING_QR_CODE' do |request, scan_result, scan_type| request.reply.text "Пользователь #{request[:FromUserName]} результат сканирования #{scan_result} тип сканирования #{scan_type}" end
on :scan, with: 'BINDING_BARCODE' do |message, scan_result| if scan_result.start_with?('CODE_39,') message.reply.text "Пользователь: #{message[:FromUserName]} сканирование штрихкода, результат #{scan_result.split(',')[1]}" end end
on :click, with: 'BOOK_LUNCH' do |request, key| request.reply.text "Пользователь: #{request[:FromUserName]} нажал #{key}" end
on :view, with: 'http://wechat.somewhere.com/view_url' do |request, view| request.reply.text "#{request[:FromUserName]} просмотрел #{view}" end
on :image do |request| request.reply.image(request[:MediaId]) # Отправка отправленного изображения обратно пользователю end # Когда пользователь отправляет голосовое сообщение on :voice do |request| # Отправка отправленного голосового сообщения обратно пользователю # request.reply.voice(request[:MediaId])
voice_id = request[:MediaId]
# Доступно только для сервисного аккаунта и должно быть активировано в панели управления.
recognition = request[:Recognition]
request.reply.text "#{voice_id} #{recognition}"
end
on :video do |request| nickname = wechat.user(request[:FromUserName])['nickname'] # Вызов API WeChat для получения имени пользователя request.reply.video(request[:MediaId], title: 'Эхо', description: "Получено от #{nickname}") # Отправка отправленного видео обратно пользователю end
on :label_location do |request| request.reply.text("Метка: #{request[:Label]} Координата X: #{request[:Location_X]} Координата Y: #{request[:Location_Y]} Масштаб: #{request[:Scale]}") end
on :location do |request| request.reply.text("Широта: #{request[:Latitude]} Долгота: #{request[:Longitude]} Точность: #{request[:Precision]}") end
on :event, with: 'unsubscribe' do |request| request.reply.success # Пользователь не сможет получить это сообщение end # Когда пользователь заходит в приложение / агентское приложение on :event, with: 'enter_agent' do |request| request.reply.text "#{request[:FromUserName]} сейчас находится в агентском приложении" end # Когда=batch_job "обновление пользователя (инкрементальная)" завершена. on :batch_job, with: 'sync_user' do |request, batch_job| request.reply.text "задача sync_user #{batch_job[:JobId]} завершена, код возврата #{batch_job[:ErrCode]}, сообщение возврата #{batch_job[:ErrMsg]}" end # Когда=batch_job "Замена пользователя (полная синхронизация)" завершена. on :batch_job, with: 'replace_user' do |request, batch_job| request.reply.text "задача replace_user #{batch_job[:JobId]} завершена, код возврата #{batch_job[:ErrCode]}, сообщение возврата #{batch_job[:ErrMsg]}" end
on :batch_job, with: 'invite_user' do |request, batch_job| request.reply.text "задача invite_user #{batch_job[:JobId]} завершена, код возврата #{batch_job[:ErrCode]}, сообщение возврата #{batch_job[:ErrMsg]}" end
on :batch_job, with: 'replace_party' do |request, batch_job| request.reply.text "задача replace_party #{batch_job[:JobId]} завершена, код возврата #{batch_job[:ErrCode]}, сообщение возврата #{batch_job[:ErrMsg]}" end
on :event, with: 'masssendjobfinish' do |request| # https://mp.weixin.qq.com/wiki?action=doc&id=mp1481187827_i0l21&t=0.03571905015619936#8 request.reply.success # запрос является хэшем результата XML. end
on :change_external_contact do |request| # https://open.work.weixin.qq.com/api/doc/90000/90135/92005 request.reply.success # запрос является хэшем результата XML. end
on :msgaudit_notify do |request| # https://open.work.weixin.qq.com/api/doc/90000/90135/95039 request.reply.success # запрос является хэшем результата XML. end # Если выше нет совпадений, будет использоваться ниже on :fallback, respond: 'сообщение по умолчанию' end
Основной важный оператор здесь — это `wechat_responder`.
Все остальное представляет собой просто DSL:
```ruby
on <message_type> do |message|
message.reply.text "текст"
end
Этот блок кода выполняется для ответа на сообщение пользователя. Следующие типы сообщений поддерживаются в настоящее время:
:with
для совпадения с содержанием текста, как в on(:текст, with:'помощь'){|сообщение, содержание| ...}
:with
для совпадения конкретного события, поддерживаются регулярные выражения для совпадения аналогично текстовому сообщению.- :локация виртуальное местоположение сообщение
- :обратный_вызов по умолчанию сообщение, когда ни один другой обработчик входящих сообщений не может его обработать, будет использоваться как обратный вызов обработчика### Передача в службу поддержки клиентов```ruby
class WechatsController < ActionController::Base
# Когда ни один другой обработчик сообщений не может принять входящее сообщение, будет передана в службу поддержки клиентов.
on :fallback do |message|
message.reply.transfer_customer_service
end
end
Внимание: не устанавливайте по умолчанию текстовый ответ, если вы хотите использовать множественную службу поддержки клиентов, иначе это приведёт к невозможности передачи текстовых сообщений.
class WechatsController < ActionController::Base
on :fallback do |message|
Rails.logger.debug "YouApp_ToUserName: #{message.message_hash['FromUserName']}"
session = WechatSession.find_by(openid: message.message_hash['FromUserName'])
return message.reply.success if session.present? && session.greeting_time.present? && session.greeting_time >= 1.week.ago
images_path = Rails.root.join('public', 'images', 'default_help.jpg')
media_id = Wechat.api.media_create('image', images_path)['media_id']
if session.present? && session.reload
# сгенерировать миграцию: add_column :wechat_sessions, :greeting_time, :datetime
session.update(greeting_time: Time.current)
end
message.reply.image(media_id)
end
end
wechat.responder.after_create
данные включают запрос <Wechat::Message>
и ответ <Wechat::Message>
.Пример:
ActiveSupport::Notifications.subscribe('wechat.responder.after_create') do |name, started, finished, unique_id, data|
WechatLog.create(request: data[:request], response: data[:response])
end
trusted_domain_fullname
и указать его на https, иначе это будет http и приведёт к недействительной подписи в JS-SDK.Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.