wechat 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 983ca9ebf1007ad2f68e079d7ed625c59a10e78198992abf84a5b9718592ff26
4
- data.tar.gz: 976751bb11aba9a0fa30674a39eaef432eb39c177a315b396d95c458c0afde45
3
+ metadata.gz: 90aad3955d68b49a3eaf8774fdc247a6f0f8c5e7887b3abde7249fd4f4d6c64b
4
+ data.tar.gz: 7c6ca0a6bd601a5527c8e99db9ddc687a4a057131dd3d6e1556ae0677781ddcd
5
5
  SHA512:
6
- metadata.gz: aeee17ba746530fbab18470172d83df90ff995ebdfa9ec92866361bbeacda03848e11a8ea278db6544ea57774513754b2dd914e7891154ca1344a03f8c5c4288
7
- data.tar.gz: c22640b41f4d4d2d2cc01b7dd3568c76d6896f976d79f3d65c2ffb9dff975cb7ed6e0463b62b1f2991b6ec80494f96e263a3d330ee5661446dec7a075e063fc7
6
+ metadata.gz: 8e83f65806db0a976da02ed4aa1bb74554af42ee0e1e9c5c9c484ec23f46a34d268dbe1396fcd2e0d6b25e70f0d99731a206ce6468a6889bc3ae523997947564
7
+ data.tar.gz: a04c6ee54cf2280e2a45bc0eea3ba2d6a1d8e45e5d02e443e2c36b524da09ec96a5b4645b7e3ecfa3c9e1754ca31a40a8683c780d4e9fcd93f417be6da70e247
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,6 +1,25 @@
1
1
  # Changelog
2
2
 
3
- ## v0.13.0 (released at 3/3/2021)
3
+ ## v0.14.0 (released at 2021-09-15)
4
+
5
+ * Add beta support for Conversation archive in WeCom, discuss at #303
6
+ * Avoid using 1.hour in early loading to improve Rails 6+ compatibility.
7
+
8
+ ## v0.13.3 (released at 2021-06-18)
9
+
10
+ * material add video description by @zlei1 #301
11
+ * Allow using http v5
12
+
13
+ ## v0.13.2 (released at 2021-04-21)
14
+
15
+ * New material_add_news API, by @zlei1 #300
16
+ * Support open_tag, by @xiajian2019 #299
17
+
18
+ ## v0.13.1 (released at 2021-03-15)
19
+
20
+ * Fix MpApi initialize bug, by @hardywu #296
21
+
22
+ ## v0.13.0 (released at 2021-03-03)
4
23
 
5
24
  * Support zeitwerk only and Rails 6+ only.
6
25
  * Support Ruby 2.6+ only.
data/README-CN.md CHANGED
@@ -1,25 +1,25 @@
1
- WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://travis-ci.com/Eric-Guo/wechat.svg)](https://travis-ci.com/github/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
1
+ WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://app.travis-ci.com/Eric-Guo/wechat.svg?branch=main)](https://travis-ci.com/github/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
2
2
  ======
3
3
 
4
4
  [![Join the chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Eric-Guo/wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
5
 
6
- WeChat gem帮助开发者方便地在Rails环境中集成[微信公众平台](https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html)、[企业微信](https://work.weixin.qq.com/api/doc)和[小程序](https://developers.weixin.qq.com/miniprogram/dev/framework/),包括功能:
6
+ WeChat Gem 帮助开发者方便地在 Rails 环境中集成[微信公众平台](https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html)、[企业微信](https://work.weixin.qq.com/api/doc)和[小程序](https://developers.weixin.qq.com/miniprogram/dev/framework/),包括功能:
7
7
 
8
- - 微信公众平台/企业微信[发送消息](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF)API(命令行和Web环境都可以使用)
9
- - [接收消息](http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%E4%B8%8E%E4%BA%8B%E4%BB%B6)(必须运行Web服务器)
10
- - [微信JS-SDK](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BE%AE%E4%BF%A1JS%E6%8E%A5%E5%8F%A3) config接口注入权限验证
11
- - OAuth 2.0认证机制
12
- - 接收消息会话(session)记录机制(可选)
8
+ - 微信公众平台/企业微信[发送消息](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF) API(命令行和 Web 环境都可以使用)
9
+ - [接收消息](http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%E4%B8%8E%E4%BA%8B%E4%BB%B6)(必须运行 Web 服务器)
10
+ - [微信JS-SDK](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BE%AE%E4%BF%A1JS%E6%8E%A5%E5%8F%A3) config 接口注入权限验证
11
+ - OAuth 2.0 认证机制
12
+ - 接收消息会话 ( Session ) 记录机制(可选)
13
13
 
14
- 命令行工具`wechat`可以调用各种无需web环境的API。同时也提供了Rails Controller的responder DSL, 可以帮助开发者方便地在Rails应用中集成微信的消息处理,包括主动推送的和被动响应的消息。
14
+ 命令行工具 `wechat` 可以调用各种无需 Web 环境的 API,同时也提供了 Rails Controller Responder DSL 。可以帮助开发者方便地在Rails 应用中集成微信的消息处理,包括主动推送的和被动响应的消息。
15
15
 
16
- 如果您的App还需要集成微信OAuth2.0, 除了简便的`wechat_oauth2`指令,也可以考虑[omniauth-wechat-oauth2](https://github.com/skinnyworm/omniauth-wechat-oauth2), 以便和devise集成,提供完整的用户认证。
16
+ 如果您的 App 还需要集成微信 OAuth2.0 除了简便的 `wechat_oauth2` 指令,也可以考虑 [omniauth-wechat-oauth2](https://github.com/skinnyworm/omniauth-wechat-oauth2) 以便和 [devise](https://github.com/heartcombo/devise) 集成提供完整的用户认证。
17
17
 
18
- 如果您对如何制作微信网页UI没有灵感,可以参考官方的[weui](https://github.com/weui/weui),针对Rails的Gem是[weui-rails](https://github.com/Eric-Guo/weui-rails)。
18
+ 如果您对如何制作微信网页 UI 没有灵感,可以参考官方的 [weui](https://github.com/weui/weui) 。针对 Rails Gem [weui-rails](https://github.com/Eric-Guo/weui-rails)。
19
19
 
20
- 主页型应用请使用[`wechat_api`](#wechat_api---rails-controller-wechat-api),传统消息型应用请使用[`wechat_responder`](#wechat_responder---rails-responder-controller-dsl)。
20
+ 主页型应用请使用 [`wechat_api`](#wechat_api---rails-controller-wechat-api),传统消息型应用请使用 [`wechat_responder`](#wechat_responder---rails-responder-controller-dsl)。
21
21
 
22
- 如果您想从一个稍微完整一些的示例开始微信开发,可以参考[wechat-starter](https://github.com/goofansu/wechat-starter),这个示例甚至包括了微信支付的内容。
22
+ 如果您想从一个稍微完整一些的示例开始微信开发,可以参考 [wechat-starter](https://github.com/goofansu/wechat-starter),这个示例甚至包括了微信支付的内容。
23
23
 
24
24
  ## 安装
25
25
 
@@ -51,24 +51,24 @@ bundle install
51
51
  rails generate wechat:install
52
52
  ```
53
53
 
54
- 运行`rails g wechat:install`后会自动生成wechat.yml配置,还有wechat controller及相关路由配置到当前Rails项目。
54
+ 运行 `rails g wechat:install` 后会自动生成 wechat.yml 配置,还有 wechats_controller 及相关路由配置到当前 Rails 项目。
55
55
 
56
- 启用session会话记录:
56
+ 启用 Session 会话记录:
57
57
 
58
58
  ```console
59
59
  rails g wechat:session
60
60
  rake db:migrate
61
61
  ```
62
62
 
63
- 运行后会自动启用回调消息会话(session)记录,wechat gem会在Rails项目中生成两个文件,用户可以在*wechat_session*表中添加更多字段或者声明一些关联关系。使用已有的**hash_store**直接保存也是可以的,但对于PostgreSQL用户,使用[hstore](http://guides.rubyonrails.org/active_record_postgresql.html#hstore)或者json格式可能更佳,当然,最佳方案仍然是添加新字段记录数据。
63
+ 运行后会自动启用回调消息会话 (Session) 记录,`wechat` Gem 会在 Rails 项目中生成两个文件,用户可以在 *wechat_session* 表中添加更多字段或者声明一些关联关系。使用已有的 **hash_store** 直接保存也是可以的,但对于 PostgreSQL 用户,使用 [hstore](http://guides.rubyonrails.org/active_record_postgresql.html#hstore) 或者 json 格式可能更佳,当然最佳方案仍然是添加新字段记录数据。
64
64
 
65
- 启用Redis存贮tokenticket:
65
+ 启用 Redis 存贮 Token Ticket:
66
66
 
67
67
  ```console
68
68
  rails g wechat:redis_store
69
69
  ```
70
70
 
71
- Redis存贮相比默认的文件存贮,可以允许Rails应用运行在多台服务器中,如果只有一台服务器,仍然推荐使用默认的文件存贮,另外命令行不会读取Redis存贮的Token或者Ticket。
71
+ Redis 存贮相比默认的文件存贮,可以允许 Rails 应用运行在多台服务器中。如果只有一台服务器,仍然推荐使用默认的文件存贮,另外命令行不会读取 Redis 存贮的 Token 或者 Ticket。
72
72
 
73
73
  启用数据库配置微信账户:
74
74
 
@@ -77,7 +77,7 @@ rails g wechat:config
77
77
  rake db:migrate
78
78
  ```
79
79
 
80
- 运行后会在数据库中创建 `wechat_configs` 表,用来记录不同微信账户的配置。
80
+ 运行后会在数据库中创建 `wechat_configs` 表用来记录不同微信账户的配置。
81
81
 
82
82
  ## 配置
83
83
 
@@ -85,13 +85,13 @@ rake db:migrate
85
85
 
86
86
  请先确保在服务器上配置成功,再到微信官网提交链接。否则微信会提示错误。
87
87
 
88
- 默认通过`rails g wechat:install`生成的URL是: `http://your-server.com/wechat`
88
+ 默认通过 `rails g wechat:install` 生成的 URL 是: `http://your-server.com/wechat`
89
89
 
90
- appid/corpid,以及secret的配置请阅读下一节
90
+ appid/corpid 以及 secret 的配置请阅读下一节
91
91
 
92
92
  #### 命令行程序的配置
93
93
 
94
- 要使用命令行程序,需要在home目录中创建一个`~/.wechat.yml`,包含以下内容。其中`access_token`是存放access_token的文件位置。
94
+ 要使用命令行程序,需要在 home 目录中创建一个 `~/.wechat.yml`,包含以下内容。其中 `access_token` 是存放 access_token 的文件位置。
95
95
 
96
96
  ```
97
97
  appid: "my_appid"
@@ -99,17 +99,17 @@ secret: "my_secret"
99
99
  access_token: "/var/tmp/wechat_access_token"
100
100
  ```
101
101
 
102
- Windows或者使用企业号,需要存放在`C:/Users/[user_name]/`下,其中corpid和corpsecret可以从企业号管理界面的设置->权限管理,通过新建任意一个管理组后获取。
102
+ Windows 或者使用企业号需要存放在 `C:/Users/[user_name]/` 下,其中 corpid corpsecret 可以从企业号管理界面的设置 -> 权限管理,通过新建任意一个管理组后获取。
103
103
 
104
104
  ```
105
105
  corpid: "my_appid"
106
106
  corpsecret: "my_secret"
107
- agentid: 1 # 企业应用的id,整型。可在应用的设置页面查看
107
+ agentid: 1 # 企业应用的 id 整型可在应用的设置页面查看
108
108
  access_token: "C:/Users/[user_name]/wechat_access_token"
109
109
  ```
110
110
 
111
111
  #### Rails 全局配置
112
- Rails应用程序中,需要将配置文件放在`config/wechat.yml`,可以为不同environment创建不同的配置。
112
+ Rails 应用程序中,需要将配置文件放在 `config/wechat.yml`,可以为不同 environment 创建不同的配置。
113
113
 
114
114
  微信公众平台配置示例:
115
115
 
@@ -145,7 +145,7 @@ default: &default
145
145
  encoding_aes_key: "my_encoding_aes_key"
146
146
  ```
147
147
 
148
- 企业微信配置下必须使用加密模式,其中token和encoding_aes_key可以从企业号管理界面的应用中心->某个应用->模式选择,选择回调模式后获得。
148
+ 企业微信配置下必须使用加密模式,其中 token encoding_aes_key 可以从企业号管理界面的应用中心 -> 某个应用 -> 模式选择,选择回调模式后获得。
149
149
 
150
150
  ```
151
151
  default: &default
@@ -196,31 +196,31 @@ test:
196
196
  # secret: "my_secret"
197
197
  ```
198
198
 
199
- 支持 微信公众平台/企业微信 多账号的注意点(例如,增加账号`wx2`):
199
+ 支持微信公众平台 / 企业微信多账号的注意点 ( 例如: 增加账号 `wx2` ):
200
200
 
201
- * 配置文件可增加多个微信公众平台(企业微信)配置,用法类似Rails中`config/database.yml`多数据库配置的处理。`development`, `test`, `production`是默认账号的配置段,要想增加账号`wx2`,你需要增加配置段`wx2_development`, `wx2_test`, `wx2_production`。
201
+ * 配置文件可增加多个微信公众平台 ( 企业微信 ) 配置,用法类似 Rails 中 `config/database.yml` 多数据库配置的处理。 `development`, `test`, `production` 是默认账号的配置段,要想增加账号 `wx2`,你需要增加配置段 `wx2_development`, `wx2_test`, `wx2_production`。
202
202
 
203
- * 声明账号`wx2`的`wechat_responder`:
203
+ * 声明账号 `wx2 `的 `wechat_responder`:
204
204
  ```ruby
205
205
  wechat_responder account: :wx2
206
206
  ```
207
207
 
208
- * `Wechat.api(:wx2)` 表示使用账号`wx2`的Wechat api,而`Wechat.api`或`Wechat.api(:default)`则表示默认账号的wechat api。
208
+ * `Wechat.api(:wx2)` 表示使用账号 `wx2` 的 Wechat api,而 `Wechat.api` 或 `Wechat.api(:default)` 则表示默认账号的 wechat api。
209
209
 
210
- * 在wechat命令行中,通过增加可选参数`-a, [--account=ACCOUNT]`来表示使用其他账号,例如`wechat users -a wx2`表示列举`wx2`这个账号的粉丝列表
210
+ * 在 wechat 命令行中,通过增加可选参数 `-a, [--account=ACCOUNT]` 来表示使用其他账号,例如 `wechat users -a wx2` 表示列举 `wx2` 这个账号的粉丝列表
211
211
 
212
- 进一步的多账号支持参见[PR 150](https://github.com/Eric-Guo/wechat/pull/150)。
212
+ 进一步的多账号支持参见 [PR 150](https://github.com/Eric-Guo/wechat/pull/150)。
213
213
 
214
214
  #### 数据库微信账户配置
215
215
  启用数据库微信配置之后,会生成如下数据表:
216
216
 
217
217
  属性 | 类型 | 备注
218
218
  ---- | ---- | ----
219
- environment | 字串 | 必填。配置对应的运行环境,一般有:`production`、`development`、`test`。比如 `production` 配置仅在生产环境有效。默认为 `development`。
220
- account | 字串 | 必填。自定义的微信账户名称。同一 `environment` 下,账户名称不允许重复。
221
- enabled | 布尔 | 必填。配置是否生效。默认 `true`。
222
- appid | 字串 | 公众号 id。此字段和 `corpid` 两者必填其一。
223
- secret | 字串 | 公众号相关配置。当公众号 `appid` 存在时必填。
219
+ environment | 字串 | 必填。配置对应的运行环境,一般有:`production`、`development`、`test`。比如 `production` 配置仅在生产环境有效。默认为 `development`。
220
+ account | 字串 | 必填。自定义的微信账户名称。同一 `environment` 下,账户名称不允许重复。
221
+ enabled | 布尔 | 必填。配置是否生效。默认 `true`。
222
+ appid | 字串 | 公众号 id , 此字段和 `corpid` 两者必填其一。
223
+ secret | 字串 | 公众号相关配置。当公众号 `appid` 存在时必填。
224
224
  corpid | 字串 | 企业号 id。此字段和 `appid` 两者必填其一。
225
225
  corpsecret | 字串 | 企业号相关配置。当企业号 `corpid` 存在时必填。
226
226
  agentid | 整数 | 企业号相关配置。当企业号 `corpid` 存在时必填。
@@ -229,7 +229,7 @@ encoding_aes_key | 字串 | 当 `encrypt_mode` 为 `true` 时必填。
229
229
  token | 字串 | 必填。
230
230
  access_token | 字串 | 必填。存储 `access token` 文件的路径。
231
231
  jsapi_ticket | 字串 | 必填。存储 `jsapi ticket` 文件的路径。
232
- skip_verify_ssl | 布尔
232
+ skip_verify_ssl | 布尔|
233
233
  timeout | 整数 | 默认值是 20。
234
234
  trusted_domain_fullname | 字串 |
235
235
 
@@ -237,21 +237,21 @@ trusted_domain_fullname | 字串 |
237
237
 
238
238
  ##### 配置优先级
239
239
 
240
- 注意在Rails项目根目录下运行`wechat`命令行工具会优先使用`config/wechat.yml`中的`default`配置,如果失败则使用`~\.wechat.yml`中的配置,以便于在生产环境下管理多个微信账号应用。
240
+ 注意在Rails项目根目录下运行 `wechat` 命令行工具会优先使用 `config/wechat.yml `中的 `default`配置,如果失败则使用 `~\.wechat.yml` 中的配置,以便于在生产环境下管理多个微信账号应用。
241
241
 
242
- 如果启用数据库账户配置,数据库中的账户信息在读入 `wechat.yml` 或环境变量之后被载入。当存在同名账户时,数据库中的配置会覆盖前两者。
242
+ 如果启用数据库账户配置,数据库中的账户信息在读入 `wechat.yml` 或环境变量之后被载入。当存在同名账户时,数据库中的配置会覆盖前两者。
243
243
 
244
244
  ##### 配置微信服务器超时
245
245
 
246
- 微信服务器有时请求会花很长时间,如果不配置,默认为20秒,可视情况配置。
246
+ 微信服务器有时请求会花很长时间,如果不配置默认为 20 秒,可视情况配置。
247
247
 
248
248
  ##### 配置跳过SSL认证
249
249
 
250
- Wechat服务器有报道曾出现[RestClient::SSLCertificateNotVerified](http://qydev.weixin.qq.com/qa/index.php?qa=11037)错误,此时可以选择关闭SSL验证。`skip_verify_ssl: true`
250
+ Wechat 服务器有报道曾出现 [RestClient::SSLCertificateNotVerified](http://qydev.weixin.qq.com/qa/index.php?qa=11037) 错误,此时可以选择关闭SSL验证。`skip_verify_ssl: true`
251
251
 
252
- #### 为每个Responder配置不同的appid和secret
252
+ #### 为每个 Responder 配置不同的 appid secret
253
253
 
254
- 有些情况下,单个Rails应用可能需要处理来自多个微信公众号的消息,您可以通过在`wechat_responder`和`wechat_api`后配置多个相关参数来支持多账号。
254
+ 有些情况下,单个 Rails 应用可能需要处理来自多个微信公众号的消息,您可以通过在 `wechat_responder` 和 `wechat_api` 后配置多个相关参数来支持多账号。
255
255
 
256
256
  ```ruby
257
257
  class WechatFirstController < ActionController::Base
@@ -276,9 +276,9 @@ end
276
276
 
277
277
  #### JS-SDK 支持
278
278
 
279
- 通过JS-SDK可以在HTML网页中控制微信客户端的行为,但必须先注入配置信息,wechat gems提供了帮助方法`wechat_config_js`使这个过程更简单:
279
+ 通过 JS-SDK 可以在 HTML 网页中控制微信客户端的行为,但必须先注入配置信息. Wechat gem 提供了帮助方法 `wechat_config_js` 使这个过程更简单:
280
280
 
281
- 注意wechat_config_js指令依赖于[`wechat_api`](#wechat_api---rails-controller-wechat-api) [`wechat_responder`](#wechat_responder---rails-responder-controller-dsl) ,需要先在controller里面添加。
281
+ 注意 wechat_config_js 指令依赖于 [`wechat_api`](#wechat_api---rails-controller-wechat-api) [`wechat_responder`](#wechat_responder---rails-responder-controller-dsl) ,需要先在 controller 里面添加。
282
282
 
283
283
  ```erb
284
284
  <body>
@@ -292,9 +292,9 @@ end
292
292
  </body>
293
293
  ```
294
294
 
295
- 在开发模式下,由于程序往往通过微信调试工具的服务器端调试工具反向代理被访问,此时需要配置`trusted_domain_fullname`以便wechat gem可以使用正确的域名做JS-SDK的权限签名。
295
+ 在开发模式下,由于程序往往通过微信调试工具的服务器端调试工具反向代理被访问,此时需要配置 `trusted_domain_fullname` 以便wechat gem 可以使用正确的域名做 JS-SDK 的权限签名。
296
296
 
297
- #### OAuth2.0验证接口支持
297
+ #### OAuth2.0 验证接口支持
298
298
 
299
299
  公众号可使用如下代码取得关注用户的相关信息。
300
300
 
@@ -307,7 +307,7 @@ class CartController < ActionController::Base
307
307
  @articles = @current_user.articles
308
308
  end
309
309
 
310
- # 指定 account_name,可以使用任意微信账户
310
+ # 指定 account_name 可以使用任意微信账户
311
311
  # wechat_oauth2('snsapi_base', nil, account_name) do |openid|
312
312
  # ...
313
313
  # end
@@ -331,27 +331,27 @@ class WechatsController < ActionController::Base
331
331
  end
332
332
  ```
333
333
 
334
- `wechat_oauth2`封装了OAuth2.0验证接口和cookie处理逻辑,用户仅需提供业务代码块即可。userid指的是微信企业成员UserID,openid是关注该公众号的用户openid。
334
+ `wechat_oauth2 `封装了 OAuth2.0 验证接口和 Cookies 处理逻辑,用户仅需提供业务代码块即可。userid 指的是微信企业成员 userid,openid 是关注该公众号的用户 openid。
335
335
 
336
336
  注意:
337
337
  * 如果使用 `wechat_responder`, 请不要在 Controller 里定义 `show` 和 `create` 方法, 否则会报错。
338
- * 如果遇到“redirect_uri参数错误”的错误信息,请登录服务号管理后台,查看“开发者中心/网页服务/网页授权获取用户基本信息”的授权回调页面域名已正确配置。
338
+ * 如果遇到“ redirect_uri 参数错误”的错误信息,请登录服务号管理后台,查看“开发者中心/网页服务/网页授权获取用户基本信息”的授权回调页面域名已正确配置。
339
339
 
340
340
  ## 关于接口权限
341
341
 
342
- wechat gems 内部不会检查权限。但因公众号类型不同,和微信服务器端通讯时,可能会被拒绝,详细权限控制可参考[官方文档](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433401084)。
342
+ Wechat Gem 内部不会检查权限, 但因公众号类型不同和微信服务器端通讯时,可能会被拒绝详细权限控制可参考[官方文档](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433401084)。
343
343
 
344
344
  ## 使用命令行
345
345
 
346
- 根据企业微信和微信公众平台配置不同,wechat提供了的命令行命令。
346
+ 根据企业微信和微信公众平台配置不同 Wechat 提供了的命令行命令。
347
347
 
348
348
  #### 微信公众平台命令行
349
349
 
350
350
  ```
351
351
  $ wechat
352
352
  Wechat Public Account commands:
353
- wechat addvoicetorecofortext [VOICE_ID] # AI开放接口-提交语音
354
- wechat callbackip # 获取微信服务器IP地址
353
+ wechat addvoicetorecofortext [VOICE_ID] # AI 开放接口 - 提交语音
354
+ wechat callbackip # 获取微信服务器 iP 地址
355
355
  wechat clear_quota # 接口调用次数清零
356
356
  wechat custom_image [OPENID, IMAGE_PATH] # 发送图片客服消息
357
357
  wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # 发送音乐客服消息
@@ -364,8 +364,9 @@ Wechat Public Account commands:
364
364
  wechat group_delete [GROUP_ID] # 删除分组
365
365
  wechat group_update [GROUP_ID, NEW_GROUP_NAME] # 修改分组名
366
366
  wechat groups # 查询所有分组
367
- wechat material_get [MEDIA_ID, PATH] # 永久媒体下载
367
+ wechat material_get [MEDIA_ID, PATH] # 永久媒体下载
368
368
  wechat material_add [MEDIA_TYPE, PATH] # 永久媒体上传
369
+ wechat material_add_news [MPNEWS_YAML_PATH] # 永久图文素材上传
369
370
  wechat material_count # 获取永久素材总数
370
371
  wechat material_delete [MEDIA_ID] # 删除永久素材
371
372
  wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
@@ -385,7 +386,7 @@ Wechat Public Account commands:
385
386
  wechat message_mass_preview [WX_NAME, MPNEWS_MEDIA_ID] # 预览图文消息素材
386
387
  wechat qrcode_create_limit_scene [SCENE_ID_OR_STR] # 请求永久二维码
387
388
  wechat qrcode_create_scene [SCENE_ID_OR_STR, EXPIRE_SECONDS] # 请求临时二维码
388
- wechat qrcode_download [TICKET, QR_CODE_PIC_PATH] # 通过ticket下载二维码
389
+ wechat qrcode_download [TICKET, QR_CODE_PIC_PATH] # 通过 ticket 下载二维码
389
390
  wechat queryrecoresultfortext [VOICE_ID] # AI开放接口-获取语音识别结果
390
391
  wechat shorturl [LONG_URL] # 长链接转短链接
391
392
  wechat tag [TAGID] # 获取标签下粉丝列表
@@ -417,10 +418,10 @@ Wechat Enterprise Account commands:
417
418
  wechat batch_replaceparty [BATCH_PARTY_CSV_MEDIA_ID] # 全量覆盖部门
418
419
  wechat batch_replaceuser [BATCH_USER_CSV_MEDIA_ID] # 全量覆盖成员
419
420
  wechat batch_syncuser [SYNC_USER_CSV_MEDIA_ID] # 增量更新成员
420
- wechat callbackip # 获取微信服务器IP地址
421
+ wechat callbackip # 获取微信服务器 iP 地址
421
422
  wechat clear_quota # 接口调用次数清零
422
- wechat convert_to_openid [USER_ID] # userid转换成openid
423
- wechat convert_to_userid [OPENID] # openid转换成userid
423
+ wechat convert_to_openid [USER_ID] # userid 转换成 openid
424
+ wechat convert_to_userid [OPENID] # openid 转换成 userid
424
425
  wechat custom_image [OPENID, IMAGE_PATH] # 发送图片客服消息
425
426
  wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # 发送音乐客服消息
426
427
  wechat custom_news [OPENID, NEWS_YAML_PATH] # 发送图文客服消息
@@ -477,7 +478,7 @@ Wechat Enterprise Account commands:
477
478
  ### 使用场景
478
479
  以下是几种典型场景的使用方法
479
480
 
480
- #####获取所有用户的OPENID
481
+ ##### 获取所有用户的 openid
481
482
 
482
483
  ```
483
484
  $ wechat users
@@ -486,7 +487,7 @@ $ wechat users
486
487
 
487
488
  ```
488
489
 
489
- #####获取用户的信息
490
+ ##### 获取用户的信息
490
491
 
491
492
  ```
492
493
  $ wechat user "oCfEht9***********"
@@ -506,7 +507,7 @@ $ wechat menu
506
507
  ##### 创建菜单
507
508
 
508
509
 
509
- 通过运行`rails g wechat:menu`可以生成一个定义菜单内容的yaml文件,菜单可以包含下列内容:
510
+ 通过运行`rails g wechat:menu`可以生成一个定义菜单内容的 yaml 文件菜单可以包含下列内容:
510
511
 
511
512
  ```
512
513
  button:
@@ -550,17 +551,17 @@ button:
550
551
  $ wechat menu_create menu.yaml
551
552
  ```
552
553
 
553
- 需确保设置,权限管理中有对此应用的管理权限,否则会报[60011](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E)错。
554
+ 需确保设置,权限管理中有对此应用的管理权限,否则会报 [60011](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E) 错。
554
555
 
555
556
  ##### 发送客服图文消息
556
- 需定义一个图文消息内容的yaml文件,比如
557
+ 需定义一个图文消息内容的 yaml 文件,比如
557
558
  articles.yaml
558
559
 
559
560
  ```
560
561
  articles:
561
562
  -
562
563
  title: "习近平在布鲁日欧洲学院演讲"
563
- description: "新华网比利时布鲁日4月1日电 国家主席习近平1日在比利时布鲁日欧洲学院发表重要演讲"
564
+ description: "新华网比利时布鲁日 4 1 日电 国家主席习近平 1 日在比利时布鲁日欧洲学院发表重要演讲"
564
565
  url: "http://news.sina.com.cn/c/2014-04-01/232629843387.shtml"
565
566
  pic_url: "http://i3.sinaimg.cn/dy/c/2014-04-01/1396366518_bYays1.jpg"
566
567
  ```
@@ -573,7 +574,7 @@ $ wechat custom_news oCfEht9oM*********** articles.yml
573
574
  ```
574
575
 
575
576
  ##### 发送模板消息
576
- 需定义一个模板消息内容的yaml文件,比如
577
+ 需定义一个模板消息内容的 yaml 文件,比如
577
578
  template.yml
578
579
 
579
580
  ```
@@ -589,10 +590,10 @@ template:
589
590
  value: "XX活动"
590
591
  color: "#CCCCCC"
591
592
  keynote2:
592
- value: "2014年9月16日"
593
+ value: "2014 9 16 日"
593
594
  color: "#CCCCCC"
594
595
  keynote3:
595
- value: "上海徐家汇xxx城"
596
+ value: "上海徐家汇 xxx 城"
596
597
  color: "#CCCCCC"
597
598
  remark:
598
599
  value: "欢迎再次使用。"
@@ -613,7 +614,7 @@ template = YAML.load(File.read(template_yaml_path))
613
614
  Wechat.api.template_message_send Wechat::Message.to(openid).template(template['template'])
614
615
  ```
615
616
 
616
- 若在Controller中使用wechat_api或者wechat_responder,可以使用wechat:
617
+ 若在 Controller 中使用 wechat_api 或者 wechat_responder,可以使用 wechat:
617
618
 
618
619
  ```ruby
619
620
  template = YAML.load(File.read(template_yaml_path))
@@ -622,7 +623,7 @@ wechat.template_message_send Wechat::Message.to(openid).template(template['templ
622
623
 
623
624
  ## wechat_api - Rails Controller Wechat API
624
625
 
625
- 虽然用户可以随时通过`Wechat.api`在任意代码中访问wechat的API功能,但是更推荐的做法是仅在controller中,通过引入`wechat_api`,使用`wechat`调用API功能,不仅因为这样是支持多个微信公众平台账号的必然要求,而且也避免了在模型层内过多引入微信相关代码。
626
+ 虽然用户可以随时通过 `Wechat.api` 在任意代码中访问 Wechat API 功能,但是更推荐的做法是仅在 Controller 中,通过引入 `wechat_api`,使用 `wechat` 调用 API 功能,不仅因为这样是支持多个微信公众平台账号的必然要求,而且也避免了在模型层内过多引入微信相关代码。
626
627
 
627
628
  ```ruby
628
629
  class WechatReportsController < ApplicationController
@@ -635,11 +636,11 @@ class WechatReportsController < ApplicationController
635
636
  end
636
637
  ```
637
638
 
638
- ## 在ActiveJob/Rake tasks中调用有wechat api
639
+ ## 在 ActiveJob/Rake tasks 中调用有 wechat api
639
640
 
640
- 可以通过`Wechat.api`在任意地方使用wechat api的功能。
641
+ 可以通过 `Wechat.api` 在任意地方使用 Wechat Api 的功能。
641
642
 
642
- 下面以通过`rails console`调用微信AI开放接口的语音识别为例:
643
+ 下面以通过 `rails console` 调用微信 Ai 开放接口的语音识别为例:
643
644
 
644
645
  ```bash
645
646
  # Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v2, 40 kbps, 16 kHz, Monaural
@@ -650,24 +651,24 @@ Wechat.api.queryrecoresultfortext 'test_voice_id'
650
651
 
651
652
  ## wechat_responder - Rails Responder Controller DSL
652
653
 
653
- 为了在Rails app中响应用户的消息,开发者需要创建一个wechat responder controller. 首先在router中定义
654
+ 为了在 Rails App 中响应用户的消息,开发者需要创建一个 wechat responder Controller 首先在 Router 中定义
654
655
 
655
656
  ```ruby
656
657
  resource :wechat, only:[:show, :create]
657
658
  ```
658
659
 
659
- 然后创建Controller class, 例如
660
+ 然后创建 Controller Class 例如
660
661
 
661
662
  ```ruby
662
663
  class WechatsController < ActionController::Base
663
664
  wechat_responder
664
665
 
665
- # 默认文字信息responder
666
+ # 默认文字信息 responder
666
667
  on :text do |request, content|
667
668
  request.reply.text "echo: #{content}" #Just echo
668
669
  end
669
670
 
670
- # 当请求的文字信息内容为'help'时, 使用这个responder处理
671
+ # 当请求的文字信息内容为 'help' 时, 使用这个 responder 处理
671
672
  on :text, with: 'help' do |request|
672
673
  request.reply.text 'help content' #回复帮助信息
673
674
  end
@@ -686,29 +687,29 @@ class WechatsController < ActionController::Base
686
687
  request.reply.text "User #{request[:FromUserName]} subscribe now"
687
688
  end
688
689
 
689
- # 公众平台收到未关注用户扫描qrscene_xxxxxx二维码时。注意此次扫描事件将不再引发上条的用户加关注事件
690
+ # 公众平台收到未关注用户扫描 qrscene_xxxxxx 二维码时。注意此次扫描事件将不再引发上条的用户加关注事件
690
691
  on :scan, with: 'qrscene_xxxxxx' do |request, ticket|
691
692
  request.reply.text "Unsubscribe user #{request[:FromUserName]} Ticket #{ticket}"
692
693
  end
693
694
 
694
- # 公众平台收到已关注用户扫描创建二维码的scene_id事件时
695
+ # 公众平台收到已关注用户扫描创建二维码的 scene_id 事件时
695
696
  on :scan, with: 'scene_id' do |request, ticket|
696
697
  request.reply.text "Subscribe user #{request[:FromUserName]} Ticket #{ticket}"
697
698
  end
698
699
 
699
- # 当没有任何on :scan事件处理已关注用户扫描的scene_id时
700
+ # 当没有任何 on :scan 事件处理已关注用户扫描的 scene_id
700
701
  on :event, with: 'scan' do |request|
701
702
  if request[:EventKey].present?
702
703
  request.reply.text "event scan got EventKey #{request[:EventKey]} Ticket #{request[:Ticket]}"
703
704
  end
704
705
  end
705
706
 
706
- # 企业微信收到EventKey 为二维码扫描结果事件时
707
+ # 企业微信收到 EventKey 为二维码扫描结果事件时
707
708
  on :scan, with: 'BINDING_QR_CODE' do |request, scan_result, scan_type|
708
709
  request.reply.text "User #{request[:FromUserName]} ScanResult #{scan_result} ScanType #{scan_type}"
709
710
  end
710
711
 
711
- # 企业微信收到EventKey 为CODE 39码扫描结果事件时
712
+ # 企业微信收到 EventKey 为 CODE 39 码扫描结果事件时
712
713
  on :scan, with: 'BINDING_BARCODE' do |message, scan_result|
713
714
  if scan_result.start_with? 'CODE_39,'
714
715
  message.reply.text "User: #{message[:FromUserName]} scan barcode, result is #{scan_result.split(',')[1]}"
@@ -736,14 +737,14 @@ class WechatsController < ActionController::Base
736
737
  # request.reply.voice(request[:MediaId])
737
738
 
738
739
  voice_id = request[:MediaId]
739
- # 开通语音识别后,用户每次发送语音给服务号时,微信会在推送的语音消息XML数据包中,增加一个Recognition字段
740
+ # 开通语音识别后,用户每次发送语音给服务号时,微信会在推送的语音消息XML数据包中,增加一个 Recognition 字段
740
741
  recognition = request[:Recognition]
741
742
  request.reply.text "#{voice_id} #{recognition}"
742
743
  end
743
744
 
744
745
  # 处理视频信息
745
746
  on :video do |request|
746
- nickname = wechat.user(request[:FromUserName])['nickname'] #调用 api 获得发送者的nickname
747
+ nickname = wechat.user(request[:FromUserName])['nickname'] #调用 api 获得发送者的 nickname
747
748
  request.reply.video(request[:MediaId], title: '回声', description: "#{nickname}发来的视频请求") #直接视频返回给用户
748
749
  end
749
750
 
@@ -793,12 +794,24 @@ class WechatsController < ActionController::Base
793
794
  request.reply.success # request is XML result hash.
794
795
  end
795
796
 
796
- # 当无任何responder处理用户信息时,使用这个responder处理
797
+ # 客户同意进行聊天内容存档事件回调
798
+ on :change_external_contact do |request|
799
+ # https://open.work.weixin.qq.com/api/doc/90000/90135/92005
800
+ request.reply.success # request is XML result hash.
801
+ end
802
+
803
+ # 会话事件回调
804
+ on :msgaudit_notify do |request|
805
+ # https://open.work.weixin.qq.com/api/doc/90000/90135/95039
806
+ request.reply.success # request is XML result hash.
807
+ end
808
+
809
+ # 当无任何 responder 处理用户信息时,使用这个 responder 处理
797
810
  on :fallback, respond: 'fallback message'
798
811
  end
799
812
  ```
800
813
 
801
- 在controller中使用`wechat_responder`引入Responder DSL, 之后可以用
814
+ controller 中使用 `wechat_responder` 引入 Responder DSL, 之后可以用
802
815
 
803
816
  ```
804
817
  on <message_type> do |message|
@@ -808,18 +821,18 @@ end
808
821
 
809
822
  来响应用户信息。
810
823
 
811
- 目前支持的message_type有如下几种
824
+ 目前支持的 message_type 有如下几种
812
825
 
813
- - :text 响应文字消息,可以用`:with`参数来匹配文本内容 `on(:text, with:'help'){|message, content| ...}`
826
+ - :text 响应文字消息,可以用 `:with` 参数来匹配文本内容 `on(:text, with:'help'){|message, content| ...}`
814
827
  - :image 响应图片消息
815
828
  - :voice 响应语音消息
816
829
  - :shortvideo 响应短视频消息
817
830
  - :video 响应视频消息
818
831
  - :label_location 响应地理位置消息
819
832
  - :link 响应链接消息
820
- - :event 响应事件消息, 可以用`:with`参数来匹配事件类型,同文字消息类似,支持正则表达式匹配
821
- - :click 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
822
- - :view 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
833
+ - :event 响应事件消息, 可以用 `:with` 参数来匹配事件类型,同文字消息类似,支持正则表达式匹配
834
+ - :click 虚拟响应事件消息, 微信传入:event,但 gem 内部会单独处理
835
+ - :view 虚拟响应事件消息, 微信传入:event,但 gem 内部会单独处理
823
836
  - :scan 虚拟响应事件消息
824
837
  - :batch_job 虚拟响应事件消息
825
838
  - :location 虚拟响应上报地理位置事件消息
@@ -836,13 +849,13 @@ class WechatsController < ActionController::Base
836
849
  end
837
850
  ```
838
851
 
839
- 注意设置了[多客服消息转发](http://dkf.qq.com/)后,不能再添加`默认文字信息responder`,否则文字消息将得不到转发。
852
+ 注意设置了[多客服消息转发](http://dkf.qq.com/)后,不能再添加默认文字信息 `responder`,否则文字消息将得不到转发。
840
853
 
841
854
  ### 通知
842
855
 
843
856
  现支持以下通知:
844
857
 
845
- * `wechat.responder.after_create` data 包含 request<Wechat::Message> 和 response<Wechat::Message>
858
+ * `wechat.responder.after_create` data 包含 request <Wechat::Message> 和 response<Wechat::Message>
846
859
 
847
860
  使用示例:
848
861
 
@@ -854,6 +867,6 @@ end
854
867
 
855
868
  ## 已知问题
856
869
 
857
- * 企业微信接受菜单消息时,Wechat腾讯服务器无法解析部分域名,请使用IP绑定回调URL,用户的普通消息目前不受影响。
858
- * 企业微信全量覆盖成员使用的csv通讯录格式,直接将下载的模板导入[是不工作的](http://qydev.weixin.qq.com/qa/index.php?qa=13978),必须使用Excel打开,然后另存为csv格式才会变成合法格式。
859
- * 如果使用nginx+unicron部署方案,并且使用了https,必须设置`trusted_domain_fullname`为https,否则会导致JS-SDK签名失效。
870
+ * 企业微信接受菜单消息时,Wechat 腾讯服务器无法解析部分域名,请使用 iP 绑定回调 URL,用户的普通消息目前不受影响。
871
+ * 企业微信全量覆盖成员使用的 CSV 通讯录格式,直接将下载的模板导入[是不工作的](http://qydev.weixin.qq.com/qa/index.php?qa=13978),必须使用 Excel 打开,然后另存为 CSV 格式才会变成合法格式。
872
+ * 如果使用 Nginx + Unicron 部署方案,并且使用了 Https,必须设置 `trusted_domain_fullname` 为 Https,否则会导致 JS-SDK 签名失效。
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://travis-ci.com/Eric-Guo/wechat.svg)](https://travis-ci.com/github/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
1
+ WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://app.travis-ci.com/Eric-Guo/wechat.svg?branch=main)](https://travis-ci.com/github/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
2
2
  ======
3
3
 
4
4
  [![Join the chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Eric-Guo/wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -395,8 +395,9 @@ Wechat Public Account commands:
395
395
  wechat group_delete [GROUP_ID] # 删除分组
396
396
  wechat group_update [GROUP_ID, NEW_GROUP_NAME] # 修改分组名
397
397
  wechat groups # 查询所有分组
398
- wechat material_get [MEDIA_ID, PATH] # 永久媒体下载
398
+ wechat material_get [MEDIA_ID, PATH] # 永久媒体下载
399
399
  wechat material_add [MEDIA_TYPE, PATH] # 永久媒体上传
400
+ wechat material_add_news [MPNEWS_YAML_PATH] # 永久图文素材上传
400
401
  wechat material_count # 获取永久素材总数
401
402
  wechat material_delete [MEDIA_ID] # 删除永久素材
402
403
  wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
@@ -827,6 +828,18 @@ class WechatsController < ActionController::Base
827
828
  request.reply.success # request is XML result hash.
828
829
  end
829
830
 
831
+ # The customer agrees to call back the chat content archive event
832
+ on :change_external_contact do |request|
833
+ # https://open.work.weixin.qq.com/api/doc/90000/90135/92005
834
+ request.reply.success # request is XML result hash.
835
+ end
836
+
837
+ # Session event callback
838
+ on :msgaudit_notify do |request|
839
+ # https://open.work.weixin.qq.com/api/doc/90000/90135/95039
840
+ request.reply.success # request is XML result hash.
841
+ end
842
+
830
843
  # If no match above will fallback to below
831
844
  on :fallback, respond: 'fallback message'
832
845
  end
data/bin/wechat CHANGED
@@ -6,8 +6,6 @@ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
6
6
  require 'thor'
7
7
  require 'wechat'
8
8
  require 'json'
9
- require 'active_support/core_ext'
10
- require 'active_support/json'
11
9
  require 'fileutils'
12
10
  require 'yaml'
13
11
  require 'cgi'
@@ -408,6 +406,12 @@ class App < Thor
408
406
  puts wechat_api.material_add(type, path)
409
407
  end
410
408
 
409
+ desc 'material_add_news [MPNEWS_YAML_PATH]', '永久图文素材上传'
410
+ def material_add_news(mpnews_yaml_path)
411
+ new = YAML.load(File.read(mpnews_yaml_path))
412
+ puts wechat_api.material_add_news(Wechat::Message.new(MsgType: 'mpnews').mpnews(new['articles']))
413
+ end
414
+
411
415
  desc 'material_delete [MEDIA_ID]', '删除永久素材'
412
416
  def material_delete(media_id)
413
417
  puts wechat_api.material_delete(media_id)
@@ -45,17 +45,18 @@ module ActionController
45
45
 
46
46
  access_token = opts[:access_token] || cfg.access_token
47
47
  jsapi_ticket = opts[:jsapi_ticket] || cfg.jsapi_ticket
48
+ qcloud_env = opts[:qcloud_env] || cfg.qcloud_env
48
49
  qcloud_token = opts[:qcloud_token] || cfg.qcloud_token
49
50
 
50
51
  api_type = opts[:type] || cfg.type
51
52
  secret = corpid.present? ? opts[:corpsecret] || cfg.corpsecret : opts[:secret] || cfg.secret
52
53
 
53
- get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_token, qcloud_token_lifespan)
54
+ get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_env, qcloud_token, qcloud_token_lifespan)
54
55
  end
55
56
 
56
- def get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_token, qcloud_token_lifespan)
57
+ def get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_env, qcloud_token, qcloud_token_lifespan)
57
58
  if api_type && api_type.to_sym == :mp
58
- Wechat::MpApi.new(appid, secret, access_token, timeout, skip_verify_ssl, jsapi_ticket, qcloud_token, qcloud_token_lifespan)
59
+ Wechat::MpApi.new(appid, secret, access_token, timeout, skip_verify_ssl, jsapi_ticket, qcloud_env, qcloud_token, qcloud_token_lifespan)
59
60
  elsif corpid.present?
60
61
  Wechat::CorpApi.new(corpid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket)
61
62
  else
@@ -61,7 +61,7 @@ module Wechat
61
61
  cfg[:timeout] ||= 20
62
62
  cfg[:qcloud_token_lifespan] ||= 7200
63
63
  cfg[:have_session_class] = class_exists?('WechatSession')
64
- cfg[:oauth2_cookie_duration] ||= 1.hour
64
+ cfg[:oauth2_cookie_duration] ||= 3600 # 1 hour
65
65
  end
66
66
 
67
67
  # create config object using raw config data
data/lib/wechat/cipher.rb CHANGED
@@ -43,7 +43,7 @@ module Wechat
43
43
  msg = decode_padding(msg)
44
44
  msg_len = msg[16, 4].reverse.unpack1('V')
45
45
  content = msg[20, msg_len]
46
- app_id = msg[(msg_len + 20)..]
46
+ app_id = msg[(msg_len + 20)..-1]
47
47
 
48
48
  [content, app_id]
49
49
  end
@@ -148,8 +148,15 @@ module Wechat
148
148
  post 'material/batchget_material', JSON.generate(type: type, offset: offset, count: count)
149
149
  end
150
150
 
151
- def material_add(type, file)
152
- post_file 'material/add_material', file, params: { type: type }
151
+ def material_add(type, file, opts = {})
152
+ params = { type: type }
153
+ params.merge!(description: opts.slice(:title, :introduction).to_json) if type == 'video'
154
+
155
+ post_file 'material/add_material', file, params: params
156
+ end
157
+
158
+ def material_add_news(mpnews_message)
159
+ post 'material/add_news', mpnews_message.to_json
153
160
  end
154
161
 
155
162
  def material_delete(media_id)
@@ -99,7 +99,7 @@ module Wechat
99
99
  form_file = file.is_a?(HTTP::FormData::File) ? file : HTTP::FormData::File.new(file)
100
100
  form_data = HTTP::FormData.create({ key: q_path,
101
101
  Signature: signature,
102
- "x-cos-security-token": x_cos_security_token,
102
+ 'x-cos-security-token': x_cos_security_token,
103
103
  'x-cos-meta-fileid': x_cos_meta_fileid,
104
104
  file: form_file })
105
105
  client.httprb.post(upload_url, form: form_data, ssl_context: client.ssl_context)
@@ -53,9 +53,9 @@ module Wechat
53
53
  yield openid, { 'openid' => openid, 'unionid' => unionid, 'access_token' => we_token }
54
54
  elsif params[:code].present? && params[:state] == oauth2_params[:state]
55
55
  access_info = wechat(account).web_access_token(params[:code])
56
- cookies.signed_or_encrypted[:we_openid] = { value: access_info['openid'], expires: self.class.oauth2_cookie_duration.from_now }
57
- cookies.signed_or_encrypted[:we_unionid] = { value: access_info['unionid'], expires: self.class.oauth2_cookie_duration.from_now }
58
- cookies.signed_or_encrypted[:we_access_token] = { value: access_info['access_token'], expires: self.class.oauth2_cookie_duration.from_now }
56
+ cookies.signed_or_encrypted[:we_openid] = { value: access_info['openid'], expires: (Time.now + self.class.oauth2_cookie_duration) }
57
+ cookies.signed_or_encrypted[:we_unionid] = { value: access_info['unionid'], expires: (Time.now + self.class.oauth2_cookie_duration) }
58
+ cookies.signed_or_encrypted[:we_access_token] = { value: access_info['access_token'], expires: (Time.now + self.class.oauth2_cookie_duration) }
59
59
  yield access_info['openid'], access_info
60
60
  else
61
61
  redirect_to generate_oauth2_url(oauth2_params), allow_other_host: true
@@ -69,8 +69,8 @@ module Wechat
69
69
  yield userid, { 'UserId' => userid, 'DeviceId' => deviceid }
70
70
  elsif params[:code].present? && params[:state] == oauth2_params[:state]
71
71
  userinfo = wechat(account).getuserinfo(params[:code])
72
- cookies.signed_or_encrypted[:we_userid] = { value: userinfo['UserId'], expires: self.class.oauth2_cookie_duration.from_now }
73
- cookies.signed_or_encrypted[:we_deviceid] = { value: userinfo['DeviceId'], expires: self.class.oauth2_cookie_duration.from_now }
72
+ cookies.signed_or_encrypted[:we_userid] = { value: userinfo['UserId'], expires: (Time.now + self.class.oauth2_cookie_duration) }
73
+ cookies.signed_or_encrypted[:we_deviceid] = { value: userinfo['DeviceId'], expires: (Time.now + self.class.oauth2_cookie_duration) }
74
74
  yield userinfo['UserId'], userinfo
75
75
  else
76
76
  redirect_to generate_oauth2_url(oauth2_params), allow_other_host: true
@@ -188,5 +188,21 @@ module Wechat
188
188
  def custom_message_send(message)
189
189
  post 'message/send', message.is_a?(Wechat::Message) ? message.agent_id(agentid).to_json : JSON.generate(message.merge(agent_id: agentid)), content_type: :json
190
190
  end
191
+
192
+ def msgaudit_get_permit_user_list(type = nil)
193
+ post 'msgaudit/get_permit_user_list', JSON.generate(type: type)
194
+ end
195
+
196
+ def msgaudit_check_single_agree(info)
197
+ post 'msgaudit/get_permit_user_list', JSON.generate(info: info)
198
+ end
199
+
200
+ def msgaudit_check_room_agree(roomid)
201
+ post 'msgaudit/check_room_agree', JSON.generate(roomid: roomid)
202
+ end
203
+
204
+ def msgaudit_groupchat(roomid)
205
+ post 'msgaudit/groupchat/get', JSON.generate(roomid: roomid)
206
+ end
191
207
  end
192
208
  end
@@ -34,7 +34,8 @@ module Wechat
34
34
  timestamp: "#{js_hash[:timestamp]}",
35
35
  nonceStr: "#{js_hash[:noncestr]}",
36
36
  signature: "#{js_hash[:signature]}",
37
- jsApiList: ['#{config_options[:api].join("','")}']
37
+ jsApiList: ['#{config_options[:api]&.join("','")}'],
38
+ openTagList: ['#{config_options[:open_tags]&.join("','")}']
38
39
  });
39
40
  WECHAT_CONFIG_JS
40
41
  javascript_tag config_js, type: 'application/javascript'
@@ -22,7 +22,7 @@ module Wechat
22
22
  def token(tries = 2)
23
23
  # Possible two worker running, one worker refresh ticket, other unaware, so must read every time
24
24
  read_qcloud_token_from_store
25
- refresh if remain_life_seconds < @random_generator.rand(30..3 * 60)
25
+ refresh if remain_life_seconds < @random_generator.rand(30..(3 * 60))
26
26
  qcloud_token
27
27
  rescue AccessTokenExpiredError
28
28
  access_token.refresh
@@ -50,6 +50,10 @@ module Wechat
50
50
  user_defined_location_responders << config
51
51
  when :label_location
52
52
  user_defined_label_location_responders << config
53
+ when :change_external_contact
54
+ user_defined_change_external_contact_responders << config
55
+ when :msgaudit_notify
56
+ user_defined_msgaudit_notify_responders << config
53
57
  else
54
58
  user_defined_responders(message_type) << config
55
59
  end
@@ -84,6 +88,14 @@ module Wechat
84
88
  @user_defined_label_location_responders ||= []
85
89
  end
86
90
 
91
+ def user_defined_change_external_contact_responders
92
+ @user_defined_change_external_contact_responders ||= []
93
+ end
94
+
95
+ def user_defined_msgaudit_notify_responders
96
+ @user_defined_msgaudit_notify_responders ||= []
97
+ end
98
+
87
99
  def user_defined_responders(type)
88
100
  @responders ||= {}
89
101
  @responders[type] ||= []
@@ -109,6 +121,10 @@ module Wechat
109
121
  yield(* user_defined_batch_job_responders(message[:BatchJob][:JobType]), message[:BatchJob])
110
122
  elsif message[:Event] == 'location'
111
123
  yield(* user_defined_location_responders, message)
124
+ elsif message[:Event] == 'change_external_contact'
125
+ yield(* user_defined_change_external_contact_responders, message)
126
+ elsif message[:Event] == 'msgaudit_notify'
127
+ yield(* user_defined_msgaudit_notify_responders, message)
112
128
  else
113
129
  yield(* match_responders(responders, message[:Event]))
114
130
  end
@@ -18,7 +18,7 @@ module Wechat
18
18
  def ticket(tries = 2)
19
19
  # Possible two worker running, one worker refresh ticket, other unaware, so must read every time
20
20
  read_ticket_from_store
21
- refresh if remain_life_seconds < @random_generator.rand(30..3 * 60)
21
+ refresh if remain_life_seconds < @random_generator.rand(30..(3 * 60))
22
22
  access_ticket
23
23
  rescue AccessTokenExpiredError
24
24
  access_token.refresh
@@ -16,7 +16,7 @@ module Wechat
16
16
  def token
17
17
  # Possible two worker running, one worker refresh token, other unaware, so must read every time
18
18
  read_token_from_store
19
- refresh if remain_life_seconds < @random_generator.rand(30..3 * 60)
19
+ refresh if remain_life_seconds < @random_generator.rand(30..(3 * 60))
20
20
  access_token
21
21
  end
22
22
 
data.tar.gz.sig CHANGED
@@ -1 +1,3 @@
1
- ;�2"pV�ε�G�7W��7T������ץ'+%��x��!9��%�}[����sVl�:c>m�n>j1y���<*�L^�Qw��jť�_��xY��|�6��g�2�h]T$<s�����'���#'��u��*��=[�3dPDH#�0�����23U�e&�r�������C[ZQh�ς=�B���\�q[dO�z� �c�QgsY��dac�4t¿l���*���.�µ�e0��땚-ٕ4\3�2�c�s�L�6�&�O]�?���!vA~<���4�^$�Ϸ�����4���o��̹����n߉����5͖����K'�ڎ/@������Ub��j�ғ#�/RL�Jvs҃&�F m'
1
+ ��i��sO+O���a�=ȷ��d:�r���Z�/ӝ]zӈ��ie,�5����b���W1Kba<|���ݝU4�#1еjh���Mpo��%Y��27r(��\%/���v]z��t�q6���!8xMGo����c� �L�|`�Fo���vA��J�F%��V�$��^�F���8�����Z.���Ȝ�& �i-�5����
2
+ 4�/E D��J�S�s�n��E<T������C;��s���>$��^�mT|l~ID��{?��j_�;K�b\����L�DA�M
3
+ aT�1��D�����PTqf5i{���<�{�^ tS��_6�!�S��NQ��� \����H�gO��`��? �vz>X�CW�
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wechat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skinnyworm
@@ -11,31 +11,31 @@ bindir: bin
11
11
  cert_chain:
12
12
  - |
13
13
  -----BEGIN CERTIFICATE-----
14
- MIIEQDCCAqigAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBplcmlj
15
- Lmd1b2N6L0RDPWdtYWlsL0RDPWNvbTAeFw0yMDA5MDIwNDUzMjFaFw0yMTA5MDIw
16
- NDUzMjFaMCUxIzAhBgNVBAMMGmVyaWMuZ3VvY3ovREM9Z21haWwvREM9Y29tMIIB
17
- ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwSfWr5RlUBlv9OuNgmxjPwhU
18
- 7eoT/m7K5h0PzUaue+dtno4WqjodoCPHF6r9hh8Ys0h1VAPu3sobH2gNaL18M0CY
19
- bmq+ik6LgH5tX2E6c2BmhMuURt2y1YvIwvx0dDOlEXll9J8ZVqGyo3Rm9AIblA3/
20
- w/V5VJGCj3XY6iipNkHHDlSWSYeD2mNr0wJW8EAUFFcyRddpotxR9Es8JwUpXdj8
21
- Bc5a/OWxKvzqLVlu76zYRYuZ41+3gWNxYF9OPnp55sNtsboGh5LJSdXZOs5+gMw9
22
- gEW/KsP4GSMlqBT7SQEO5EH3qjp3aatHaMT8Fq9h3AnNESQMubMWtlPqEYyrYkli
23
- wr8A8SGiX3rCkNG0cc4zVsagtXm4csbSeaIjLV57LA2sKngI4/kw55UYlloAtGPh
24
- qNEqsPLbN/RkyS1zQjf14mQBpBt3SdxnT7YDSPIYiAPTtLuThcy3Flgh6cDX1RH7
25
- FQPZJzQ7pSb/3Edj+VBaYhpo+y4ySLxx9DOLfm6lAgMBAAGjezB5MAkGA1UdEwQC
26
- MAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBRWBfZurpq8AmvpfBq7eSA0ivhotDAf
27
- BgNVHREEGDAWgRRlcmljLmd1b2N6QGdtYWlsLmNvbTAfBgNVHRIEGDAWgRRlcmlj
28
- Lmd1b2N6QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAJ1tLpEqCXma9fFeU
29
- l6N4tEDrwYVxdbkXgOScUZBsagNlEM9vvskygivKu8AV8ffdtsg9OAuhdfAjPjX+
30
- GvGnmuoweHFTsIrOhNryqFDgvkufBczmFLOskjRuzt4NoBNgge8+xoNo+N9o/0jz
31
- GZi69Dth2i92rffuEzyFbfA9xzkjL+uSqJRJVDP5UbIWGnQ99M4GfplJZWRkmoX9
32
- 5Ek/ZVhzEz6kdZuZErloYKqjWWvFHUFAYmJd3fqKpb468yTIaL4bl4aUl2+xLdyK
33
- fPI/ZWGy2uNjffzbrhJ+Ti6qAdubkJoMIqrfbrFV1ew2Bxkp/93etXVNjAgHNmu1
34
- o3VAf3sbhnj33jAri7JYx/1MhAcJXlvpKxX9QnYouxU/RgzBF7oqcT0dJ2jWUnAI
35
- spvOK5/LPXWX6ZGc2SR8SH/s7ftYH2EkeM1VUbtemow08NdgCwJ4IG+fRQ9dcrJ+
36
- L9TbpLHvVrCe1w8duMqNeUmqj+M1iC/5Zst2vIe14QcOTuAh
14
+ MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhlcmlj
15
+ L0RDPWNsb3VkLW1lcy9EQz1jb20wHhcNMjEwOTE1MDIxMDMzWhcNMjIwOTE1MDIx
16
+ MDMzWjAjMSEwHwYDVQQDDBhlcmljL0RDPWNsb3VkLW1lcy9EQz1jb20wggGiMA0G
17
+ CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDfweHJdAqu5+BQ6t+F923czZvUynqe
18
+ DyacqWVUbDg53oVwYxldDNqUea5hMlSs1UWj2sJ5ZHiU02ly0QVyDCw/5pFP2CKJ
19
+ ukQbw35ZoCF0t2i0/GPYAtBMxb1qUynkxDAtCefQG33lBt2u9scgE9xOIiPrxtJg
20
+ shl3XFYmOx1ol66JR540l7NBS1OHR7UV6WiJrRW1cZTcR+py7jIbo6ud/rhZVHCO
21
+ B2RTZtpH1I7ilknT1/NXMX6aw+XoNda4w+4lsrHfqKssfwJcsGMq1IbbG8illxRT
22
+ wsYLiUXNJaAacT9HVO4B0jIFPP5Me7FIkiqZZKr7uyHNQE0S/5OOUkIM0v5kkUOF
23
+ IE+A6WwVCyi05+JNcbLuxeSZnNeqQcXiqxl1RcodIJxw0VTcSE1CO2eYCsvfzLJ2
24
+ fn9fLaSA/mrosg72UV126GeXu/y/N6gf3F6ZHM2qAMZhJ9ZUR03bUVIqApsJN28g
25
+ JOkm/lV0PutN0Y2UrD0gSKxgrN24ZSsWlBECAwEAAaN3MHUwCQYDVR0TBAIwADAL
26
+ BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFHHJIHijHoPxeoZDyGAvLbBalVvoMB0GA1Ud
27
+ EQQWMBSBEmVyaWNAY2xvdWQtbWVzLmNvbTAdBgNVHRIEFjAUgRJlcmljQGNsb3Vk
28
+ LW1lcy5jb20wDQYJKoZIhvcNAQELBQADggGBACYpors2s6sGEq0ErgijhSkAQRoj
29
+ W1EO3ORYYyCRFPFX1KLtUpFuXi/1rZoMoSug2Lpr+GWqt7eZIwNoryjYMbuE/sOn
30
+ sANkOvLx8x4RMlmTFe+WkPiV9NasFqNn7EBSpjqQRWRlCuh6rMiYzzxNbbNvbRT4
31
+ WMhBf7eWRpr1TBXDr51E8RtA+LG6wZuJFnKWBisgKOmpUw79f7EvIQAGS3MEWk/g
32
+ fSvIf14zM5Dw0whGa/n60jgSc5yiW3/75GXt8608BK+bs5dViJ/3ofuIhqpOvvdp
33
+ 4Oiv2zIXsfUIGAIwHN5mLwAwHty1d0s8Kt0jtJAXDUODgTuXaBj/aOqTZUUgp8Kv
34
+ 6SoPdaa0LFPbkI2eiUN1xUPelsgKz0kyRBJtkMnSKFxcCxw7VHGRGFsw0ORZodQ3
35
+ ZM9IDtdMg8E/4ujwilV8HKmgU77vVN6vSMvxx8zQFSz9a6GbdpB4egPZ++peSk/Q
36
+ uaIJtOX6M4VC6u7eZfotARKyUy6EcoN2zNqEAQ==
37
37
  -----END CERTIFICATE-----
38
- date: 2021-03-03 00:00:00.000000000 Z
38
+ date: 2021-09-15 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: activesupport
@@ -66,7 +66,7 @@ dependencies:
66
66
  version: 1.0.4
67
67
  - - "<"
68
68
  - !ruby/object:Gem::Version
69
- version: '5'
69
+ version: '6'
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: 1.0.4
77
77
  - - "<"
78
78
  - !ruby/object:Gem::Version
79
- version: '5'
79
+ version: '6'
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: nokogiri
82
82
  requirement: !ruby/object:Gem::Requirement
@@ -167,14 +167,14 @@ dependencies:
167
167
  requirements:
168
168
  - - "~>"
169
169
  - !ruby/object:Gem::Version
170
- version: '4.0'
170
+ version: '5.0'
171
171
  type: :development
172
172
  prerelease: false
173
173
  version_requirements: !ruby/object:Gem::Requirement
174
174
  requirements:
175
175
  - - "~>"
176
176
  - !ruby/object:Gem::Version
177
- version: '4.0'
177
+ version: '5.0'
178
178
  - !ruby/object:Gem::Dependency
179
179
  name: sqlite3
180
180
  requirement: !ruby/object:Gem::Requirement
@@ -258,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
258
258
  - !ruby/object:Gem::Version
259
259
  version: '0'
260
260
  requirements: []
261
- rubygems_version: 3.2.12
261
+ rubygems_version: 3.2.27
262
262
  signing_key:
263
263
  specification_version: 4
264
264
  summary: DSL for wechat message handling and API
metadata.gz.sig CHANGED
Binary file