wechat 0.6.7 → 0.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eee061e4522d5960256e017183c61f615ef94a0d
4
- data.tar.gz: 510a350df936a6d4d9465997ba253b4ef3e78634
3
+ metadata.gz: eda1d074591c670445ef8e73291eb2131e0a595c
4
+ data.tar.gz: 576db68d3550ab9ac86c392e2ca6757184e0b114
5
5
  SHA512:
6
- metadata.gz: f21668a1dc3cbb3fac9336e57d214a4d9d99a1814e30e1474b1a0e9d12dd47c47bc69c5f6af02c4b6bb89f09ab76ade708ebaebfb838eba4110268730ac69688
7
- data.tar.gz: efa6851ddb7f3f948daccdc148c412f8a73e2211c123c4417ddd3e7195cdeb3030e8f046162328e3c11ded6b96cf3c5143e35d92757fe6770f530ef18ed876a4
6
+ metadata.gz: 70af013d27c8a9a144012c564da1d02927d865fcc64837d1bfb371f525503527d830ac80cb53a512927980e717780a8e88d31f15853a4210eb70780d5a7c716e
7
+ data.tar.gz: c38169bac4eca6015b9be377d95b3b4ae44511ed3df80ae379d76d3b23077e44867da3c98a15437fb447b6a99757479a4e501cc393e2e87bfda8b5279eb4e9e8
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.6.8 (released at 12/25/2015)
4
+
5
+ * Support Rails 5.0.0.beta1.
6
+ * English README available
7
+ * Fix oauth2_url calling error, fix #75
8
+
3
9
  ## v0.6.7 (released at 12/18/2015)
4
10
 
5
11
  * Add timeout configuration option, close #74
@@ -0,0 +1,584 @@
1
+ WeChat [![Gem Version][version-badge]][rubygems] [![Build Status][travis-badge]][travis] [![Code Climate][codeclimate-badge]][codeclimate] [![Code Coverage][codecoverage-badge]][codecoverage]
2
+ ======
3
+
4
+ [![Join the chat][gitter-badge]][gitter] [![Issue Stats][issue-badge]][issuestats] [![PR Stats][pr-badge]][issuestats]
5
+
6
+ WeChat gem 可以帮助开发者方便地在Rails环境中集成微信[公众平台](https://mp.weixin.qq.com/)和[企业平台](https://qy.weixin.qq.com)提供的服务,包括:
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
+
13
+ 命令行工具`wechat`可以调用各种无需web环境的API。同时也提供了Rails Controller的responder DSL, 可以帮助开发者方便地在Rails应用中集成微信的消息处理,包括主动推送的和被动响应的消息。
14
+
15
+ 如果你的App还需要集成微信OAuth2.0, 你可以考虑[omniauth-wechat-oauth2](https://github.com/skinnyworm/omniauth-wechat-oauth2), 以便和devise集成,提供完整的用户认证。
16
+
17
+ 如果你对如何制作微信网页UI没有灵感,可以参考官方的[weui](https://github.com/weui/weui),针对Rails的Gem是[weui-rails](https://github.com/Eric-Guo/weui-rails)。
18
+
19
+
20
+ ## 安装
21
+
22
+ Using `gem install`
23
+
24
+ ```
25
+ gem install "wechat"
26
+ ```
27
+
28
+ Or add to your app's `Gemfile`:
29
+
30
+ ```
31
+ gem 'wechat'
32
+ ```
33
+
34
+ Run the following command to install it:
35
+
36
+ ```console
37
+ bundle install
38
+ ```
39
+
40
+ Run the generator:
41
+
42
+ ```console
43
+ rails generate wechat:install
44
+ ```
45
+
46
+ 运行`rails g wechat:install`后会自动生成wechat.yml配置,还有wechat controller及相关路由配置到当前Rails项目。
47
+
48
+
49
+ ## 配置
50
+
51
+ #### 命令行程序的配置
52
+
53
+ 要使用命令行程序,需要在home目录中创建一个`~/.wechat.yml`,包含以下内容。其中`access_token`是存放access_token的文件位置。
54
+
55
+ ```
56
+ appid: "my_appid"
57
+ secret: "my_secret"
58
+ access_token: "/var/tmp/wechat_access_token"
59
+ ```
60
+
61
+ Windows或者使用企业号,需要存放在`C:/Users/[user_name]/`下,其中corpid和corpsecret可以从企业号管理界面的设置->权限管理,通过新建任意一个管理组后获取。
62
+
63
+ ```
64
+ corpid: "my_appid"
65
+ corpsecret: "my_secret"
66
+ agentid: 1 # 企业应用的id,整型。可在应用的设置页面查看
67
+ access_token: "C:/Users/[user_name]/wechat_access_token"
68
+ ```
69
+
70
+ #### Rails 全局配置
71
+ Rails应用程序中,需要将配置文件放在`config/wechat.yml`,可以为不同environment创建不同的配置。
72
+
73
+ 公众号配置示例:
74
+
75
+ ```
76
+ default: &default
77
+ appid: "app_id"
78
+ secret: "app_secret"
79
+ token: "app_token"
80
+ access_token: "/var/tmp/wechat_access_token"
81
+
82
+ production:
83
+ appid: <%= ENV['WECHAT_APPID'] %>
84
+ secret: <%= ENV['WECHAT_APP_SECRET'] %>
85
+ token: <%= ENV['WECHAT_TOKEN'] %>
86
+ access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %>
87
+
88
+ development:
89
+ <<: *default
90
+
91
+ test:
92
+ <<: *default
93
+ ```
94
+
95
+ 公众号可选安全模式(加密模式),通过添加如下配置可开启加密模式。
96
+
97
+ ```
98
+ default: &default
99
+ encrypt_mode: true
100
+ encoding_aes_key: "my_encoding_aes_key"
101
+ ```
102
+
103
+ 企业号配置下必须使用加密模式,其中token和encoding_aes_key可以从企业号管理界面的应用中心->某个应用->模式选择,选择回调模式后获得。
104
+
105
+ ```
106
+ default: &default
107
+ corpid: "corpid"
108
+ corpsecret: "corpsecret"
109
+ agentid: 1
110
+ access_token: "C:/Users/[user_name]/wechat_access_token"
111
+ token: ""
112
+ encoding_aes_key: ""
113
+ jsapi_ticket: "C:/Users/[user_name]/wechat_jsapi_ticket"
114
+
115
+ production:
116
+ corpid: <%= ENV['WECHAT_CORPID'] %>
117
+ corpsecret: <%= ENV['WECHAT_CORPSECRET'] %>
118
+ agentid: <%= ENV['WECHAT_AGENTID'] %>
119
+ access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %>
120
+ token: <%= ENV['WECHAT_TOKEN'] %>
121
+ timeout: 30,
122
+ skip_verify_ssl: true
123
+ encoding_aes_key: <%= ENV['WECHAT_ENCODING_AES_KEY'] %>
124
+ jsapi_ticket: <%= ENV['WECHAT_JSAPI_TICKET'] %>
125
+
126
+ development:
127
+ <<: *default
128
+
129
+ test:
130
+ <<: *default
131
+ ```
132
+
133
+ ##### 配置优先级
134
+
135
+ 注意在Rails项目根目录下运行`wechat`命令行工具会优先使用`config/wechat.yml`中的`default`配置,如果失败则使用`~\.wechat.yml`中的配置,以便于在生产环境下管理多个微信账号应用。
136
+
137
+ ##### 配置微信服务器超时
138
+
139
+ 微信服务器有时请求会花很长时间,如果不配置,默认为20秒,可视情况配置。
140
+
141
+ ##### 配置跳过SSL认证
142
+
143
+ Wechat服务器有报道曾出现[RestClient::SSLCertificateNotVerified](http://qydev.weixin.qq.com/qa/index.php?qa=11037)错误,此时可以选择关闭SSL验证。`skip_verify_ssl: true`
144
+
145
+ #### 为每个Responder配置不同的appid和secret
146
+
147
+ 在个别情况下,单个Rails应用可能需要处理来自多个账号的消息,此时可以配置多个responder controller。
148
+
149
+ ```ruby
150
+ class WechatFirstController < ActionController::Base
151
+ wechat_responder appid: "app1", secret: "secret1", token: "token1", access_token: Rails.root.join("tmp/access_token1")
152
+
153
+ on :text, with:"help", respond: "help content"
154
+ end
155
+ ```
156
+
157
+ #### jssdk 支持
158
+
159
+ jssdk 使用前需通过config接口注入权限验证配置, 所需参数可以通过 signature 方法获取:
160
+
161
+ ```ruby
162
+ WechatsController.wechat.jsapi_ticket.signature(request.original_url)
163
+ ```
164
+
165
+ ## 关于接口权限
166
+
167
+ wechat gems 内部不会检查权限。但因公众号类型不同,和微信服务器端通讯时,可能会被拒绝,详细权限控制可参考[官方文档](http://mp.weixin.qq.com/wiki/7/2d301d4b757dedc333b9a9854b457b47.html)。
168
+
169
+ ## 使用命令行
170
+
171
+ 根据企业号和公众号配置不同,wechat提供了的命令行命令。
172
+
173
+ #### 公众号命令行
174
+
175
+ ```
176
+ $ wechat
177
+ Wechat commands:
178
+ wechat callbackip # 获取微信服务器IP地址
179
+ wechat custom_image [OPENID, IMAGE_PATH] # 发送图片客服消息
180
+ wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # 发送音乐客服消息
181
+ wechat custom_news [OPENID, NEWS_YAML_PATH] # 发送图文客服消息
182
+ wechat custom_text [OPENID, TEXT_MESSAGE] # 发送文字客服消息
183
+ wechat custom_video [OPENID, VIDEO_PATH] # 发送视频客服消息
184
+ wechat custom_voice [OPENID, VOICE_PATH] # 发送语音客服消息
185
+ wechat group_create [GROUP_NAME] # 创建分组
186
+ wechat group_delete [GROUP_ID] # 删除分组
187
+ wechat group_update [GROUP_ID, NEW_GROUP_NAME] # 修改分组名
188
+ wechat groups # 查询所有分组
189
+ wechat material [MEDIA_ID, PATH] # 永久媒体下载
190
+ wechat material_add [MEDIA_TYPE, PATH] # 永久媒体上传
191
+ wechat material_count # 获取永久素材总数
192
+ wechat material_delete [MEDIA_ID] # 删除永久素材
193
+ wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
194
+ wechat media [MEDIA_ID, PATH] # 媒体下载
195
+ wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
196
+ wechat menu # 当前菜单
197
+ wechat menu_create [MENU_YAML_PATH] # 创建菜单
198
+ wechat menu_delete # 删除菜单
199
+ wechat oauth2_url [REDIRECT_URI] # 生成OAuth2.0验证URL
200
+ wechat qrcode_create_limit_scene [SCENE_ID_OR_STR] # 请求永久二维码
201
+ wechat qrcode_create_scene [SCENE_ID, EXPIRE_SECONDS] # 请求临时二维码
202
+ wechat qrcode_download [TICKET, QR_CODE_PIC_PATH] # 通过ticket下载二维码
203
+ wechat template_message [OPENID, TEMPLATE_YAML_PATH] # 模板消息接口
204
+ wechat user [OPEN_ID] # 获取用户基本信息
205
+ wechat user_change_group [OPEN_ID, TO_GROUP_ID] # 移动用户分组
206
+ wechat user_group [OPEN_ID] # 查询用户所在分组
207
+ wechat user_update_remark [OPEN_ID, REMARK] # 设置备注名
208
+ wechat users # 关注者列表
209
+ ```
210
+
211
+ #### 企业号命令行
212
+ ```
213
+ $ wechat
214
+ Wechat commands:
215
+ wechat agent [AGENT_ID] # 获取企业号应用详情
216
+ wechat agent_list # 获取应用概况列表
217
+ wechat batch_job_result [JOB_ID] # 获取异步任务结果
218
+ wechat batch_replaceparty [BATCH_PARTY_CSV_MEDIA_ID] # 全量覆盖部门
219
+ wechat batch_replaceuser [BATCH_USER_CSV_MEDIA_ID] # 全量覆盖成员
220
+ wechat batch_syncuser [SYNC_USER_CSV_MEDIA_ID] # 增量更新成员
221
+ wechat callbackip # 获取微信服务器IP地址
222
+ wechat convert_to_openid [USER_ID] # userid转换成openid
223
+ wechat custom_image [OPENID, IMAGE_PATH] # 发送图片客服消息
224
+ wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # 发送音乐客服消息
225
+ wechat custom_news [OPENID, NEWS_YAML_PATH] # 发送图文客服消息
226
+ wechat custom_text [OPENID, TEXT_MESSAGE] # 发送文字客服消息
227
+ wechat custom_video [OPENID, VIDEO_PATH] # 发送视频客服消息
228
+ wechat custom_voice [OPENID, VOICE_PATH] # 发送语音客服消息
229
+ wechat department [DEPARTMENT_ID] # 获取部门列表
230
+ wechat department_create [NAME, PARENT_ID] # 创建部门
231
+ wechat department_delete [DEPARTMENT_ID] # 删除部门
232
+ wechat department_update [DEPARTMENT_ID, NAME] # 更新部门
233
+ wechat invite_user [USER_ID] # 邀请成员关注
234
+ wechat material [MEDIA_ID, PATH] # 永久媒体下载
235
+ wechat material_add [MEDIA_TYPE, PATH] # 永久媒体上传
236
+ wechat material_count # 获取永久素材总数
237
+ wechat material_delete [MEDIA_ID] # 删除永久素材
238
+ wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
239
+ wechat media [MEDIA_ID, PATH] # 媒体下载
240
+ wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
241
+ wechat menu # 当前菜单
242
+ wechat menu_create [MENU_YAML_PATH] # 创建菜单
243
+ wechat menu_delete # 删除菜单
244
+ wechat message_send [OPENID, TEXT_MESSAGE] # 发送文字消息
245
+ wechat oauth2_url [REDIRECT_URI] # 生成OAuth2.0验证URL
246
+ wechat qrcode_download [TICKET, QR_CODE_PIC_PATH] # 通过ticket下载二维码
247
+ wechat tag [TAG_ID] # 获取标签成员
248
+ wechat tag_add_department [TAG_ID, PARTY_IDS] # 增加标签部门
249
+ wechat tag_add_user [TAG_ID, USER_IDS] # 增加标签成员
250
+ wechat tag_create [TAGNAME, TAG_ID] # 创建标签
251
+ wechat tag_del_department [TAG_ID, PARTY_IDS] # 删除标签部门
252
+ wechat tag_del_user [TAG_ID, USER_IDS] # 删除标签成员
253
+ wechat tag_delete [TAG_ID] # 删除标签
254
+ wechat tag_update [TAG_ID, TAGNAME] # 更新标签名字
255
+ wechat tags # 获取标签列表
256
+ wechat template_message [OPENID, TEMPLATE_YAML_PATH] # 模板消息接口
257
+ wechat upload_replaceparty [BATCH_PARTY_CSV_PATH] # 上传文件方式全量覆盖部门
258
+ wechat upload_replaceuser [BATCH_USER_CSV_PATH] # 上传文件方式全量覆盖成员
259
+ wechat user [OPEN_ID] # 获取用户基本信息
260
+ wechat user_batchdelete [USER_ID_LIST] # 批量删除成员
261
+ wechat user_delete [USER_ID] # 删除成员
262
+ wechat user_list [DEPARTMENT_ID] # 获取部门成员详情
263
+ wechat user_simplelist [DEPARTMENT_ID] # 获取部门成员
264
+ wechat user_update_remark [OPEN_ID, REMARK] # 设置备注名
265
+ ```
266
+
267
+ ### 使用场景
268
+ 以下是几种典型场景的使用方法
269
+
270
+ #####获取所有用户的OPENID
271
+
272
+ ```
273
+ $ wechat users
274
+
275
+ {"total"=>4, "count"=>4, "data"=>{"openid"=>["oCfEht9***********", "oCfEhtwqa***********", "oCfEht9oMCqGo***********", "oCfEht_81H5o2***********"]}, "next_openid"=>"oCfEht_81H5o2***********"}
276
+
277
+ ```
278
+
279
+ #####获取用户的信息
280
+
281
+ ```
282
+ $ wechat user "oCfEht9***********"
283
+
284
+ {"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}
285
+
286
+ ```
287
+
288
+ ##### 获取当前菜单
289
+ ```
290
+ $ wechat menu
291
+
292
+ {"menu"=>{"button"=>[{"type"=>"view", "name"=>"保护的", "url"=>"http://***/protected", "sub_button"=>[]}, {"type"=>"view", "name"=>"公开的", "url"=>"http://***", "sub_button"=>[]}]}}
293
+
294
+ ```
295
+
296
+ ##### 创建菜单
297
+ 创建菜单需要一个定义菜单内容的yaml文件,比如
298
+ menu.yaml
299
+
300
+ ```
301
+ button:
302
+ -
303
+ name: "我要"
304
+ sub_button:
305
+ -
306
+ type: "scancode_waitmsg"
307
+ name: "绑定用餐二维码"
308
+ key: "BINDING_QR_CODE"
309
+ -
310
+ type: "click"
311
+ name: "预订午餐"
312
+ key: "BOOK_LUNCH"
313
+ -
314
+ type: "click"
315
+ name: "预订晚餐"
316
+ key: "BOOK_DINNER"
317
+ -
318
+ name: "查询"
319
+ sub_button:
320
+ -
321
+ type: "click"
322
+ name: "进出记录"
323
+ key: "BADGE_IN_OUT"
324
+ -
325
+ type: "click"
326
+ name: "年假余额"
327
+ key: "ANNUAL_LEAVE"
328
+ -
329
+ type: "view"
330
+ name: "关于"
331
+ url: "http://blog.cloud-mes.com/"
332
+ ```
333
+
334
+ 然后执行命令行,需确保设置,权限管理中有对此应用的管理权限,否则会报[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)错。
335
+
336
+ ```
337
+ $ wechat menu_create menu.yaml
338
+
339
+ ```
340
+
341
+ ##### 发送客服图文消息
342
+ 需定义一个图文消息内容的yaml文件,比如
343
+ articles.yaml
344
+
345
+ ```
346
+ articles:
347
+ -
348
+ title: "习近平在布鲁日欧洲学院演讲"
349
+ description: "新华网比利时布鲁日4月1日电 国家主席习近平1日在比利时布鲁日欧洲学院发表重要演讲"
350
+ url: "http://news.sina.com.cn/c/2014-04-01/232629843387.shtml"
351
+ pic_url: "http://i3.sinaimg.cn/dy/c/2014-04-01/1396366518_bYays1.jpg"
352
+ ```
353
+
354
+ 然后执行命令行
355
+
356
+ ```
357
+ $ wechat custom_news oCfEht9oM*********** articles.yml
358
+
359
+ ```
360
+
361
+ ##### 发送模板消息
362
+ 需定义一个模板消息内容的yaml文件,比如
363
+ template.yml
364
+
365
+ ```
366
+ template:
367
+ template_id: "o64KQ62_xxxxxxxxxxxxxxx-Qz-MlNcRKteq8"
368
+ url: "http://weixin.qq.com/download"
369
+ topcolor: "#FF0000"
370
+ data:
371
+ first:
372
+ value: "你好,你已报名成功"
373
+ color: "#0A0A0A"
374
+ keynote1:
375
+ value: "XX活动"
376
+ color: "#CCCCCC"
377
+ keynote2:
378
+ value: "2014年9月16日"
379
+ color: "#CCCCCC"
380
+ keynote3:
381
+ value: "上海徐家汇xxx城"
382
+ color: "#CCCCCC"
383
+ remark:
384
+ value: "欢迎再次使用。"
385
+ color: "#173177"
386
+
387
+ ```
388
+
389
+ 然后执行命令行
390
+
391
+ ```
392
+ $ wechat template_message oCfEht9oM*********** template.yml
393
+ ```
394
+
395
+ ## Rails Responder Controller DSL
396
+
397
+ 为了在Rails app中响应用户的消息,开发者需要创建一个wechat responder controller. 首先在router中定义
398
+
399
+ ```ruby
400
+ resource :wechat, only:[:show, :create]
401
+ ```
402
+
403
+ 然后创建Controller class, 例如
404
+
405
+ ```ruby
406
+ class WechatsController < ActionController::Base
407
+ wechat_responder
408
+
409
+ # 默认文字信息responder
410
+ on :text do |request, content|
411
+ request.reply.text "echo: #{content}" #Just echo
412
+ end
413
+
414
+ # 当请求的文字信息内容为'help'时, 使用这个responder处理
415
+ on :text, with: 'help' do |request|
416
+ request.reply.text 'help content' #回复帮助信息
417
+ end
418
+
419
+ # 当请求的文字信息内容为'<n>条新闻'时, 使用这个responder处理, 并将n作为第二个参数
420
+ on :text, with: /^(\d+)条新闻$/ do |request, count|
421
+ # 微信最多显示10条新闻,大于10条将只取前10条
422
+ news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: '新闻标题', content: "第#{n}条新闻的内容#{n.hash}" } }
423
+ request.reply.news(news) do |article, n, index| # 回复"articles"
424
+ article.item title: "#{index} #{n[:title]}", description: n[:content], pic_url: 'http://www.baidu.com/img/bdlogo.gif', url: 'http://www.baidu.com/'
425
+ end
426
+ end
427
+
428
+ # 当用户加关注
429
+ on :event, with: 'subscribe' do |request|
430
+ request.reply.text "User #{request[:FromUserName]} subscribe now"
431
+ end
432
+
433
+ # 公众号收到未关注用户扫描qrscene_xxxxxx二维码时。注意此次扫描事件将不再引发上条的用户加关注事件
434
+ on :scan, with: 'qrscene_xxxxxx' do |request, ticket|
435
+ request.reply.text "Unsubscribe user #{request[:FromUserName]} Ticket #{ticket}"
436
+ end
437
+
438
+ # 公众号收到已关注用户扫描创建二维码的scene_id事件时
439
+ on :scan, with: 'scene_id' do |request, ticket|
440
+ request.reply.text "Subscribe user #{request[:FromUserName]} Ticket #{ticket}"
441
+ end
442
+
443
+ # 当没有任何on :scan事件处理已关注用户扫描的scene_id时
444
+ on :event, with: 'scan' do |request|
445
+ if request[:EventKey].present?
446
+ request.reply.text "event scan got EventKey #{request[:EventKey]} Ticket #{request[:Ticket]}"
447
+ end
448
+ end
449
+
450
+ # 企业号收到EventKey 为二维码扫描结果事件时
451
+ on :scan, with: 'BINDING_QR_CODE' do |request, scan_result, scan_type|
452
+ request.reply.text "User #{request[:FromUserName]} ScanResult #{scan_result} ScanType #{scan_type}"
453
+ end
454
+
455
+ # 企业号收到EventKey 为CODE 39码扫描结果事件时
456
+ on :scan, with: 'BINDING_BARCODE' do |message, scan_result|
457
+ if scan_result.start_with? 'CODE_39,'
458
+ message.reply.text "User: #{message[:FromUserName]} scan barcode, result is #{scan_result.split(',')[1]}"
459
+ end
460
+ end
461
+
462
+ # 当用户点击菜单时
463
+ on :click, with: 'BOOK_LUNCH' do |request, key|
464
+ request.reply.text "User: #{request[:FromUserName]} click #{key}"
465
+ end
466
+
467
+ # 当用户点击菜单时
468
+ on :view, with: 'http://wechat.somewhere.com/view_url' do |request, view|
469
+ request.reply.text "#{request[:FromUserName]} view #{view}"
470
+ end
471
+
472
+ # 处理图片信息
473
+ on :image do |request|
474
+ request.reply.image(request[:MediaId]) #直接将图片返回给用户
475
+ end
476
+
477
+ # 处理语音信息
478
+ on :voice do |request|
479
+ request.reply.voice(request[:MediaId]) #直接语音音返回给用户
480
+ end
481
+
482
+ # 处理视频信息
483
+ on :video do |request|
484
+ nickname = wechat.user(request[:FromUserName])['nickname'] #调用 api 获得发送者的nickname
485
+ request.reply.video(request[:MediaId], title: '回声', description: "#{nickname}发来的视频请求") #直接视频返回给用户
486
+ end
487
+
488
+ # 处理上报地理位置事件
489
+ on :location do |request|
490
+ request.reply.text("Latitude: #{message[:Latitude]} Longitude: #{message[:Longitude]} Precision: #{message[:Precision]}")
491
+ end
492
+
493
+ # 当用户取消关注订阅
494
+ on :event, with: 'unsubscribe' do |request|
495
+ request.reply.success # user can not receive this message
496
+ end
497
+
498
+ # 成员进入应用的事件推送
499
+ on :event, with: 'enter_agent' do |request|
500
+ request.reply.text "#{request[:FromUserName]} enter agent app now"
501
+ end
502
+
503
+ # 当异步任务增量更新成员完成时推送
504
+ on :batch_job, with: 'sync_user' do |request, batch_job|
505
+ request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
506
+ end
507
+
508
+ # 当异步任务全量覆盖成员完成时推送
509
+ on :batch_job, with: 'replace_user' do |request, batch_job|
510
+ request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
511
+ end
512
+
513
+ # 当异步任务邀请成员关注完成时推送
514
+ on :batch_job, with: 'invite_user' do |request, batch_job|
515
+ request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
516
+ end
517
+
518
+ # 当异步任务全量覆盖部门完成时推送
519
+ on :batch_job, with: 'replace_party' do |request, batch_job|
520
+ request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
521
+ end
522
+
523
+ # 当无任何responder处理用户信息时,使用这个responder处理
524
+ on :fallback, respond: 'fallback message'
525
+ end
526
+ ```
527
+
528
+ 在controller中使用`wechat_responder`引入Responder DSL, 之后可以用
529
+
530
+ ```
531
+ on <message_type> do |message|
532
+ message.reply.text "some text"
533
+ end
534
+ ```
535
+
536
+ 来响应用户信息。
537
+
538
+ 目前支持的message_type有如下几种
539
+
540
+ - :text 响应文字消息,可以用`:with`参数来匹配文本内容 `on(:text, with:'help'){|message, content| ...}`
541
+ - :image 响应图片消息
542
+ - :voice 响应语音消息
543
+ - :video 响应视频消息
544
+ - :link 响应链接消息
545
+ - :event 响应事件消息, 可以用`:with`参数来匹配事件类型
546
+ - :click 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
547
+ - :view 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
548
+ - :scan 虚拟响应事件消息
549
+ - :batch_job 虚拟响应事件消息
550
+ - :location 虚拟响应上报地理位置事件消息
551
+ - :fallback 默认响应,当收到的消息无法被其他responder响应时,会使用这个responder.
552
+
553
+ ### 多客服消息转发
554
+
555
+ ```ruby
556
+ class WechatsController < ActionController::Base
557
+ # 当无任何responder处理用户信息时,转发至客服处理。
558
+ on :fallback do |message|
559
+ message.reply.transfer_customer_service
560
+ end
561
+ end
562
+ ```
563
+
564
+ 注意设置了[多客服消息转发](http://dkf.qq.com/)后,不能再添加`默认文字信息responder`,否则文字消息将得不到转发。
565
+
566
+ ## 已知问题
567
+
568
+ * 企业号接受菜单消息时,Wechat腾讯服务器无法解析部分域名,请使用IP绑定回调URL,用户的普通消息目前不受影响。
569
+ * 企业号全量覆盖成员使用的csv通讯录格式,直接将下载的模板导入[是不工作的](http://qydev.weixin.qq.com/qa/index.php?qa=13978),必须使用Excel打开,然后另存为csv格式才会变成合法格式。
570
+
571
+
572
+ [version-badge]: https://badge.fury.io/rb/wechat.svg
573
+ [rubygems]: https://rubygems.org/gems/wechat
574
+ [travis-badge]: https://travis-ci.org/Eric-Guo/wechat.svg
575
+ [travis]: https://travis-ci.org/Eric-Guo/wechat
576
+ [codeclimate-badge]: https://codeclimate.com/github/Eric-Guo/wechat.png
577
+ [codeclimate]: https://codeclimate.com/github/Eric-Guo/wechat
578
+ [codecoverage-badge]: https://codeclimate.com/github/Eric-Guo/wechat/coverage.png
579
+ [codecoverage]: https://codeclimate.com/github/Eric-Guo/wechat/coverage
580
+ [gitter-badge]: https://badges.gitter.im/Join%20Chat.svg
581
+ [gitter]: https://gitter.im/Eric-Guo/wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
582
+ [issue-badge]: http://issuestats.com/github/Eric-Guo/wechat/badge/issue
583
+ [pr-badge]: http://issuestats.com/github/Eric-Guo/wechat/badge/pr
584
+ [issuestats]: http://issuestats.com/github/Eric-Guo/wechat
data/README.md CHANGED
@@ -3,21 +3,27 @@ WeChat [![Gem Version][version-badge]][rubygems] [![Build Status][travis-badge]]
3
3
 
4
4
  [![Join the chat][gitter-badge]][gitter] [![Issue Stats][issue-badge]][issuestats] [![PR Stats][pr-badge]][issuestats]
5
5
 
6
- WeChat gem 可以帮助开发者方便地在Rails环境中集成微信[公众平台](https://mp.weixin.qq.com/)和[企业平台](https://qy.weixin.qq.com)提供的服务,包括:
6
+ [中文文档 Chinese document](/README-CN.md)
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认证机制
8
+ [Wechat](http://www.wechat.com/) is a free messaging and calling app developed by [Tencent](http://tencent.com/en-us/index.shtml), after linked billion people, Wechat become a platform of application
12
9
 
13
- 命令行工具`wechat`可以调用各种无需web环境的API。同时也提供了Rails Controller的responder DSL, 可以帮助开发者方便地在Rails应用中集成微信的消息处理机制。
10
+ WeChat gem trying to helping Rails developer to integrated [enterprise account](https://qy.weixin.qq.com) / [public account](https://mp.weixin.qq.com/) easily. Below feature is ready and no need writing adapter code talking to wechat server directly.
14
11
 
15
- 如果你的App还需要集成微信OAuth2.0, 你可以考虑[omniauth-wechat-oauth2](https://github.com/skinnyworm/omniauth-wechat-oauth2), 以便和devise集成,提供完整的用户认证。
12
+ - [Sending message](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF) API(Can access via console or in rails)
13
+ - [Receiving message](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)(You must running on rails server to receiving message)
14
+ - [Wechat JS-SDK](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BE%AE%E4%BF%A1JS%E6%8E%A5%E5%8F%A3) config signature
15
+ - OAuth 2.0 authentication
16
16
 
17
- 如果你对如何制作微信网页UI没有灵感,可以参考官方的[weui](https://github.com/weui/weui),针对Rails的Gem是[weui-rails](https://github.com/Eric-Guo/weui-rails)。
18
17
 
18
+ `wechat` command share the same API in console, so you can interactive with wechat server quickly, without starting up web environment/code.
19
19
 
20
- ## 安装
20
+ A responder DSL can used in Rails controller, so giving a event based interface to handler message sent by end user from wechat server.
21
+
22
+ Wechat provide OAuth2.0 as authentication service and possible to intergrated with devise/other authorization gems, [omniauth-wechat-oauth2](https://github.com/skinnyworm/omniauth-wechat-oauth2) is a good start
23
+
24
+ There is official [weui](https://github.com/weui/weui), which corresponding Rails gems called [weui-rails](https://github.com/Eric-Guo/weui-rails) available, if you prefer following the same UI design as wechat.
25
+
26
+ ## Installation
21
27
 
22
28
  Using `gem install`
23
29
 
@@ -43,14 +49,14 @@ Run the generator:
43
49
  rails generate wechat:install
44
50
  ```
45
51
 
46
- 运行`rails g wechat:install`后会自动生成wechat.yml配置,还有wechat controller及相关路由配置到当前Rails项目。
52
+ `rails g wechat:install` will generated the initial `wechat.yml` configuration, example wechat controller and corresponding routes.
47
53
 
48
54
 
49
- ## 配置
55
+ ## Configuration
50
56
 
51
- #### 命令行程序的配置
57
+ #### Configure for command line
52
58
 
53
- 要使用命令行程序,需要在home目录中创建一个`~/.wechat.yml`,包含以下内容。其中`access_token`是存放access_token的文件位置。
59
+ You can using `wechat` command solely, you need created configure file `~/.wechat.yml` and including below content for public account. the access_token will be write as a file.
54
60
 
55
61
  ```
56
62
  appid: "my_appid"
@@ -58,19 +64,22 @@ secret: "my_secret"
58
64
  access_token: "/var/tmp/wechat_access_token"
59
65
  ```
60
66
 
61
- Windows或者使用企业号,需要存放在`C:/Users/[user_name]/`下,其中corpidcorpsecret可以从企业号管理界面的设置->权限管理,通过新建任意一个管理组后获取。
67
+ For enterprise account, need using `corpid` instead of `appid` as enterprise account support multiply application (Tencent called agent) in one enterprise account. Obtain the `corpsecret` is a little tricky, must created at management mode->privilege setting and create any of management group to obtain. Due to Tencent currently only provide Chinese interface for they management console, it's highly recommend you find a college knowing Mandarin to help you to obtain.
68
+
69
+ Windows user need store `.wechat.yml` at `C:/Users/[user_name]/` (replace your user name), also be caution the direction of folder separator.
62
70
 
63
71
  ```
64
72
  corpid: "my_appid"
65
73
  corpsecret: "my_secret"
66
- agentid: 1 # 企业应用的id,整型。可在应用的设置页面查看
74
+ agentid: 1 # Integer, which can be obtain from application, settings
67
75
  access_token: "C:/Users/[user_name]/wechat_access_token"
68
76
  ```
69
77
 
70
- #### Rails 全局配置
71
- Rails应用程序中,需要将配置文件放在`config/wechat.yml`,可以为不同environment创建不同的配置。
78
+ #### Configure for Rails
72
79
 
73
- 公众号配置示例:
80
+ Rails configuration files support different environment similar to database.yml, after running `rails generate wechat:install` you can find configuration files at `config/wechat.yml`
81
+
82
+ Public account congfigure example:
74
83
 
75
84
  ```
76
85
  default: &default
@@ -92,7 +101,8 @@ test:
92
101
  <<: *default
93
102
  ```
94
103
 
95
- 公众号可选安全模式(加密模式),通过添加如下配置可开启加密模式。
104
+ Although it's optional for public account, but highly recommend to enable encrypt mode by add below two items to `wechat.yml`
105
+
96
106
 
97
107
  ```
98
108
  default: &default
@@ -100,7 +110,9 @@ default: &default
100
110
  encoding_aes_key: "my_encoding_aes_key"
101
111
  ```
102
112
 
103
- 企业号配置下必须使用加密模式,其中token和encoding_aes_key可以从企业号管理界面的应用中心->某个应用->模式选择,选择回调模式后获得。
113
+ Enterprise account must using encrypt mode (`encrypt_mode: true` is default on, no need configure).
114
+
115
+ The `token` and `encoding_aes_key` can be obtain from management console -> one of the agent application -> Mode selection, select callback mode and get/set.
104
116
 
105
117
  ```
106
118
  default: &default
@@ -119,7 +131,7 @@ production:
119
131
  access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %>
120
132
  token: <%= ENV['WECHAT_TOKEN'] %>
121
133
  timeout: 30,
122
- skip_verify_ssl: true
134
+ skip_verify_ssl: true # not recommend
123
135
  encoding_aes_key: <%= ENV['WECHAT_ENCODING_AES_KEY'] %>
124
136
  jsapi_ticket: <%= ENV['WECHAT_JSAPI_TICKET'] %>
125
137
 
@@ -130,21 +142,21 @@ test:
130
142
  <<: *default
131
143
  ```
132
144
 
133
- ##### 配置优先级
145
+ ##### Configure priority
134
146
 
135
- 注意在Rails项目根目录下运行`wechat`命令行工具会优先使用`config/wechat.yml`中的`default`配置,如果失败则使用`~\.wechat.yml`中的配置,以便于在生产环境下管理多个微信账号应用。
147
+ Running `wechat` command in the root folder of Rails application will using the Rails configuration first (`default` section), if can not find it, will relay on `~\.wechat.yml`, such behavior enable manage more wechat public account and enterprise account without changing your home `~\.wechat.yml` file.
136
148
 
137
- ##### 配置微信服务器超时
149
+ ##### Wechat server timeout setting
138
150
 
139
- 微信服务器有时请求会花很长时间,如果不配置,默认为20秒,可视情况配置。
151
+ Stability various even for Tencent wechat server, so setting a long timeout may needed, default is 20 seconds if not set.
140
152
 
141
- ##### 配置跳过SSL认证
153
+ ##### Skip the SSL verification
142
154
 
143
- Wechat服务器有报道曾出现[RestClient::SSLCertificateNotVerified](http://qydev.weixin.qq.com/qa/index.php?qa=11037)错误,此时可以选择关闭SSL验证。`skip_verify_ssl: true`
155
+ SSL Certification can also be corrupted by some reason in China, [it's reported](http://qydev.weixin.qq.com/qa/index.php?qa=11037) and if it's happen to you, can setting `skip_verify_ssl: true`. (not recommend)
144
156
 
145
- #### 为每个Responder配置不同的appid和secret
157
+ #### Configure individual responder with different appid
146
158
 
147
- 在个别情况下,单个Rails应用可能需要处理来自多个账号的消息,此时可以配置多个responder controller。
159
+ Rare case, you may want to hosting more than one wechat enterprise/public account in one Rails application, so you can given those configuration info when calling `wechat_responder`
148
160
 
149
161
  ```ruby
150
162
  class WechatFirstController < ActionController::Base
@@ -154,23 +166,25 @@ class WechatFirstController < ActionController::Base
154
166
  end
155
167
  ```
156
168
 
157
- #### jssdk 支持
169
+ #### JS-SDK helper
158
170
 
159
- jssdk 使用前需通过config接口注入权限验证配置, 所需参数可以通过 signature 方法获取:
171
+ JS-SDK enable you control wechat behavior in your web page, but need inject a config with signature methods first, you can obtain those signature hash via below
160
172
 
161
173
  ```ruby
162
174
  WechatsController.wechat.jsapi_ticket.signature(request.original_url)
163
175
  ```
164
176
 
165
- ## 关于接口权限
177
+ ## The API privilege
166
178
 
167
- wechat gems 内部不会检查权限。但因公众号类型不同,和微信服务器端通讯时,可能会被拒绝,详细权限控制可参考[官方文档](http://mp.weixin.qq.com/wiki/7/2d301d4b757dedc333b9a9854b457b47.html)
179
+ wechat gems won't handle any privilege exception. (except token time out, but it's not important to you as it's auto retry/recovery in gems internally), but Tencent will control a lot of privilege based on your public account type and certification, more info, please reference [official document](http://mp.weixin.qq.com/wiki/7/2d301d4b757dedc333b9a9854b457b47.html).
168
180
 
169
- ## 使用命令行
181
+ ## Command line mode
170
182
 
171
- 根据企业号和公众号配置不同,wechat提供了的命令行命令。
183
+ The available API is different between public account and enterprise account, so wechat gems provide different set of command.
172
184
 
173
- #### 公众号命令行
185
+ Feel safe if you can not read Chinese in the comments, it's keep there in order to copy & find in official document more easier.
186
+
187
+ #### Public account command line
174
188
 
175
189
  ```
176
190
  $ wechat
@@ -208,7 +222,7 @@ Wechat commands:
208
222
  wechat users # 关注者列表
209
223
  ```
210
224
 
211
- #### 企业号命令行
225
+ #### Enterprise account command line
212
226
  ```
213
227
  $ wechat
214
228
  Wechat commands:
@@ -264,10 +278,9 @@ Wechat commands:
264
278
  wechat user_update_remark [OPEN_ID, REMARK] # 设置备注名
265
279
  ```
266
280
 
267
- ### 使用场景
268
- 以下是几种典型场景的使用方法
281
+ ### Command line usage demo (partially)
269
282
 
270
- #####获取所有用户的OPENID
283
+ ##### Fetch all users open id
271
284
 
272
285
  ```
273
286
  $ wechat users
@@ -276,7 +289,7 @@ $ wechat users
276
289
 
277
290
  ```
278
291
 
279
- #####获取用户的信息
292
+ ##### Fetch user info
280
293
 
281
294
  ```
282
295
  $ wechat user "oCfEht9***********"
@@ -285,15 +298,7 @@ $ wechat user "oCfEht9***********"
285
298
 
286
299
  ```
287
300
 
288
- #####获取用户的信息
289
-
290
- ```
291
- $ wechat user "oCfEht9***********"
292
-
293
- {"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}
294
- ```
295
-
296
- ##### 获取当前菜单
301
+ ##### Fetch menu
297
302
  ```
298
303
  $ wechat menu
299
304
 
@@ -301,14 +306,14 @@ $ wechat menu
301
306
 
302
307
  ```
303
308
 
304
- ##### 创建菜单
305
- 创建菜单需要一个定义菜单内容的yaml文件,比如
306
- menu.yaml
309
+ ##### Menu create
310
+
311
+ menu content for a wechat application can be defined as a yaml files, like `menu.yaml`
307
312
 
308
313
  ```
309
314
  button:
310
315
  -
311
- name: "我要"
316
+ name: "Want"
312
317
  sub_button:
313
318
  -
314
319
  type: "scancode_waitmsg"
@@ -323,7 +328,7 @@ button:
323
328
  name: "预订晚餐"
324
329
  key: "BOOK_DINNER"
325
330
  -
326
- name: "查询"
331
+ name: "Query"
327
332
  sub_button:
328
333
  -
329
334
  type: "click"
@@ -335,20 +340,20 @@ button:
335
340
  key: "ANNUAL_LEAVE"
336
341
  -
337
342
  type: "view"
338
- name: "关于"
343
+ name: "About"
339
344
  url: "http://blog.cloud-mes.com/"
340
345
  ```
341
346
 
342
- 然后执行命令行,需确保设置,权限管理中有对此应用的管理权限,否则会报[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)错。
347
+ Caution: make sure you having management privilege for those application below running below command, other will got [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) error.
343
348
 
344
349
  ```
345
350
  $ wechat menu_create menu.yaml
346
-
347
351
  ```
348
352
 
349
- ##### 发送客服图文消息
350
- 需定义一个图文消息内容的yaml文件,比如
351
- articles.yaml
353
+ ##### Sent custom news
354
+
355
+
356
+ Sending custom_news should also defined as a yaml file, like `articles.yaml`
352
357
 
353
358
  ```
354
359
  articles:
@@ -359,16 +364,16 @@ articles:
359
364
  pic_url: "http://i3.sinaimg.cn/dy/c/2014-04-01/1396366518_bYays1.jpg"
360
365
  ```
361
366
 
362
- 然后执行命令行
367
+ After that, can running command:
363
368
 
364
369
  ```
365
370
  $ wechat custom_news oCfEht9oM*********** articles.yml
366
371
 
367
372
  ```
368
373
 
369
- ##### 发送模板消息
370
- 需定义一个模板消息内容的yaml文件,比如
371
- template.yml
374
+ ##### Sent template message
375
+
376
+ Sending template message via yaml file similar too, defined `template.yml` and content is just the template content.
372
377
 
373
378
  ```
374
379
  template:
@@ -377,24 +382,24 @@ template:
377
382
  topcolor: "#FF0000"
378
383
  data:
379
384
  first:
380
- value: "你好,你已报名成功"
385
+ value: "Hello, you successfully registed"
381
386
  color: "#0A0A0A"
382
387
  keynote1:
383
- value: "XX活动"
388
+ value: "5km Health Running"
384
389
  color: "#CCCCCC"
385
390
  keynote2:
386
- value: "2014年9月16"
391
+ value: "2014-09-16"
387
392
  color: "#CCCCCC"
388
393
  keynote3:
389
- value: "上海徐家汇xxx城"
394
+ value: "Centry Park, Pudong, Shanghai"
390
395
  color: "#CCCCCC"
391
396
  remark:
392
- value: "欢迎再次使用。"
397
+ value: "Welcome back"
393
398
  color: "#173177"
394
399
 
395
400
  ```
396
401
 
397
- 然后执行命令行
402
+ After that, can running command:
398
403
 
399
404
  ```
400
405
  $ wechat template_message oCfEht9oM*********** template.yml
@@ -402,138 +407,138 @@ $ wechat template_message oCfEht9oM*********** template.yml
402
407
 
403
408
  ## Rails Responder Controller DSL
404
409
 
405
- 为了在Rails app中响应用户的消息,开发者需要创建一个wechat responder controller. 首先在router中定义
410
+ In order to responding the message user sent, Rails developer need create a wechat responder controller and defined the routing in `routes.rb`
406
411
 
407
412
  ```ruby
408
413
  resource :wechat, only:[:show, :create]
409
414
  ```
410
415
 
411
- 然后创建Controller class, 例如
416
+ So the ActionController should defined like below:
412
417
 
413
418
  ```ruby
414
419
  class WechatsController < ActionController::Base
415
420
  wechat_responder
416
-
417
- # 默认文字信息responder
421
+ wechat_responder
422
+
423
+ # default text responder when no other match
418
424
  on :text do |request, content|
419
- request.reply.text "echo: #{content}" #Just echo
425
+ request.reply.text "echo: #{content}" # Just echo
420
426
  end
421
427
 
422
- # 当请求的文字信息内容为'help'时, 使用这个responder处理
428
+ # When receive 'help', will trigger this responder
423
429
  on :text, with: 'help' do |request|
424
- request.reply.text 'help content' #回复帮助信息
430
+ request.reply.text 'help content'
425
431
  end
426
432
 
427
- # 当请求的文字信息内容为'<n>条新闻'时, 使用这个responder处理, 并将n作为第二个参数
428
- on :text, with: /^(\d+)条新闻$/ do |request, count|
429
- # 微信最多显示10条新闻,大于10条将只取前10条
430
- news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: '新闻标题', content: "第#{n}条新闻的内容#{n.hash}" } }
431
- request.reply.news(news) do |article, n, index| # 回复"articles"
433
+ # When receive '<n>news', will match and will got count as <n> as parameter
434
+ on :text, with: /^(\d+) news$/ do |request, count|
435
+ # Wechat article can only contain max 10 items, large than 10 will dropped.
436
+ news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: 'News title', content: "No. #{n} news content" } }
437
+ request.reply.news(news) do |article, n, index| # article is return object
432
438
  article.item title: "#{index} #{n[:title]}", description: n[:content], pic_url: 'http://www.baidu.com/img/bdlogo.gif', url: 'http://www.baidu.com/'
433
439
  end
434
440
  end
435
441
 
436
- # 当用户加关注
437
442
  on :event, with: 'subscribe' do |request|
438
- request.reply.text "User #{request[:FromUserName]} subscribe now"
443
+ request.reply.text "#{request[:FromUserName]} subscribe now"
439
444
  end
440
445
 
441
- # 公众号收到未关注用户扫描qrscene_xxxxxx二维码时。注意此次扫描事件将不再引发上条的用户加关注事件
446
+ # When unsubscribe user scan qrcode qrscene_xxxxxx to subscribe in public account
447
+ # notice user will subscribe public account at same time, so wechat won't trigger subscribe event any more
442
448
  on :scan, with: 'qrscene_xxxxxx' do |request, ticket|
443
449
  request.reply.text "Unsubscribe user #{request[:FromUserName]} Ticket #{ticket}"
444
450
  end
445
451
 
446
- # 公众号收到已关注用户扫描创建二维码的scene_id事件时
452
+ # When subscribe user scan scene_id in public account
447
453
  on :scan, with: 'scene_id' do |request, ticket|
448
454
  request.reply.text "Subscribe user #{request[:FromUserName]} Ticket #{ticket}"
449
455
  end
450
456
 
451
- # 当没有任何on :scan事件处理已关注用户扫描的scene_id
457
+ # When no any on :scan responder can match subscribe user scaned scene_id
452
458
  on :event, with: 'scan' do |request|
453
459
  if request[:EventKey].present?
454
460
  request.reply.text "event scan got EventKey #{request[:EventKey]} Ticket #{request[:Ticket]}"
455
461
  end
456
462
  end
457
463
 
458
- # 企业号收到EventKey 为二维码扫描结果事件时
464
+ # When enterprise user press menu BINDING_QR_CODE and success to scan bar code
459
465
  on :scan, with: 'BINDING_QR_CODE' do |request, scan_result, scan_type|
460
466
  request.reply.text "User #{request[:FromUserName]} ScanResult #{scan_result} ScanType #{scan_type}"
461
467
  end
462
468
 
463
- # 企业号收到EventKey 为CODE 39码扫描结果事件时
469
+ # Except QR code, wechat can also scan CODE_39 bar code in enterprise account
464
470
  on :scan, with: 'BINDING_BARCODE' do |message, scan_result|
465
471
  if scan_result.start_with? 'CODE_39,'
466
472
  message.reply.text "User: #{message[:FromUserName]} scan barcode, result is #{scan_result.split(',')[1]}"
467
473
  end
468
474
  end
469
475
 
470
- # 当用户点击菜单时
476
+ # When user click the menu button
471
477
  on :click, with: 'BOOK_LUNCH' do |request, key|
472
478
  request.reply.text "User: #{request[:FromUserName]} click #{key}"
473
479
  end
474
480
 
475
- # 当用户点击菜单时
481
+ # When user view URL in the menu button
476
482
  on :view, with: 'http://wechat.somewhere.com/view_url' do |request, view|
477
483
  request.reply.text "#{request[:FromUserName]} view #{view}"
478
484
  end
479
485
 
480
- # 处理图片信息
486
+ # When user sent the imsage
481
487
  on :image do |request|
482
- request.reply.image(request[:MediaId]) #直接将图片返回给用户
488
+ request.reply.image(request[:MediaId]) # Echo the sent image to user
483
489
  end
484
490
 
485
- # 处理语音信息
491
+ # When user sent the voice
486
492
  on :voice do |request|
487
- request.reply.voice(request[:MediaId]) #直接语音音返回给用户
493
+ request.reply.voice(request[:MediaId]) # Echo the sent voice to user
488
494
  end
489
495
 
490
- # 处理视频信息
496
+ # When user sent the video
491
497
  on :video do |request|
492
- nickname = wechat.user(request[:FromUserName])['nickname'] #调用 api 获得发送者的nickname
493
- request.reply.video(request[:MediaId], title: '回声', description: "#{nickname}发来的视频请求") #直接视频返回给用户
498
+ nickname = wechat.user(request[:FromUserName])['nickname'] # Call wechat api to get sender nickname
499
+ request.reply.video(request[:MediaId], title: 'Echo', description: "Got #{nickname} sent video") # Echo the sent video to user
494
500
  end
495
501
 
496
- # 处理上报地理位置事件
502
+ # When user sent location
497
503
  on :location do |request|
498
504
  request.reply.text("Latitude: #{message[:Latitude]} Longitude: #{message[:Longitude]} Precision: #{message[:Precision]}")
499
505
  end
500
506
 
501
- # 当用户取消关注订阅
502
507
  on :event, with: 'unsubscribe' do |request|
503
508
  request.reply.success # user can not receive this message
504
509
  end
505
510
 
506
- # 成员进入应用的事件推送
511
+ # When user enter the app / agent app
507
512
  on :event, with: 'enter_agent' do |request|
508
513
  request.reply.text "#{request[:FromUserName]} enter agent app now"
509
514
  end
510
515
 
511
- # 当异步任务增量更新成员完成时推送
516
+ # When batch job create/update user (incremental) finished.
512
517
  on :batch_job, with: 'sync_user' do |request, batch_job|
513
- request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
518
+ request.reply.text "sync_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
514
519
  end
515
520
 
516
- # 当异步任务全量覆盖成员完成时推送
521
+ # When batch job replace user (full sync) finished.
517
522
  on :batch_job, with: 'replace_user' do |request, batch_job|
518
- request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
523
+ request.reply.text "replace_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
519
524
  end
520
525
 
521
- # 当异步任务邀请成员关注完成时推送
526
+ # When batch job invent user finished.
522
527
  on :batch_job, with: 'invite_user' do |request, batch_job|
523
- request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
528
+ request.reply.text "invite_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
524
529
  end
525
530
 
526
- # 当异步任务全量覆盖部门完成时推送
531
+ # When batch job replace department (full sync) finished.
527
532
  on :batch_job, with: 'replace_party' do |request, batch_job|
528
- request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
533
+ request.reply.text "replace_party job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
529
534
  end
530
535
 
531
- # 当无任何responder处理用户信息时,使用这个responder处理
536
+ # Any not match above will fail to below
532
537
  on :fallback, respond: 'fallback message'
533
538
  end
534
539
  ```
535
540
 
536
- 在controller中使用`wechat_responder`引入Responder DSL, 之后可以用
541
+ So the importent statement is only `wechat_responder`, all other is just a DSL:
537
542
 
538
543
  ```
539
544
  on <message_type> do |message|
@@ -541,46 +546,42 @@ on <message_type> do |message|
541
546
  end
542
547
  ```
543
548
 
544
- 来响应用户信息。
549
+ The block code will be running to responding user's message.
545
550
 
546
- 目前支持的message_type有如下几种
547
551
 
548
- - :text 响应文字消息,可以用`:with`参数来匹配文本内容 `on(:text, with:'help'){|message, content| ...}`
549
- - :image 响应图片消息
550
- - :voice 响应语音消息
551
- - :video 响应视频消息
552
- - :link 响应链接消息
553
- - :event 响应事件消息, 可以用`:with`参数来匹配事件类型
554
- - :click 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
555
- - :view 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
556
- - :scan 虚拟响应事件消息
557
- - :batch_job 虚拟响应事件消息
558
- - :location 虚拟响应上报地理位置事件消息
559
- - :fallback 默认响应,当收到的消息无法被其他responder响应时,会使用这个responder.
552
+ Below is current supported message_type:
560
553
 
561
- ### 多客服消息转发
554
+ - :text text message, using `:with` to match text content like `on(:text, with:'help'){|message, content| ...}`
555
+ - :image image message
556
+ - :voice voice message
557
+ - :video video message
558
+ - :link link message
559
+ - :event event message, using `:with` to match particular event
560
+ - :click virtual event message, wechat still sent event message,but gems will mapping to menu click event.
561
+ - :view virtual view message, wechat still sent event message,but gems will mapping to menu view page event.
562
+ - :scan virtual scan message, wechat still sent event message, but gems will mapping on scan event
563
+ - :batch_job virtual batch job message
564
+ - :location virtual location message
565
+ - :fallback default message, when no other responder can handle incoming messsage, will using fallback to handle
566
+
567
+ ### Transfer to customer service
562
568
 
563
569
  ```ruby
564
570
  class WechatsController < ActionController::Base
565
- # 当无任何responder处理用户信息时,转发至客服处理。
571
+ # When no other responder can handle incoming message, will transfer to human customer service.
566
572
  on :fallback do |message|
567
- message.reply.transfer_customer_service
573
+ message.reply.transfer_customer_service
568
574
  end
569
575
  end
570
576
  ```
571
577
 
572
- 注意设置了[多客服消息转发](http://dkf.qq.com/)后,不能再添加`默认文字信息responder`,否则文字消息将得不到转发。
573
-
574
- ## Message DSL
575
-
576
- Wechat 的核心是一个Message DSL,帮助开发者构建各种类型的消息,包括主动推送的和被动响应的。
577
- ....
578
+ Caution: do not setting default text responder if you want to using [multiply human customer service](http://dkf.qq.com/), other will lead text message can not transfer.
578
579
 
579
580
 
580
- ## 已知问题
581
+ ## Known Issue
581
582
 
582
- * 企业号接受菜单消息时,Wechat腾讯服务器无法解析部分域名,请使用IP绑定回调URL,用户的普通消息目前不受影响。
583
- * 企业号全量覆盖成员使用的csv通讯录格式,直接将下载的模板导入[是不工作的](http://qydev.weixin.qq.com/qa/index.php?qa=13978),必须使用Excel打开,然后另存为csv格式才会变成合法格式。
583
+ * Sometime, enterprise account can not receive the menu message due to Tencent server can not resolved the DNS, so using IP as a callback URL more stable, but it's never happen for user sent text message.
584
+ * Enterprise batch replace users using a CSV format file, but if you using the download template directly, it's [not working](http://qydev.weixin.qq.com/qa/index.php?qa=13978), must open the CSV file in excel first, then save as CSV format again, seems Tencent only support Excel save as CSV file format.
584
585
 
585
586
 
586
587
  [version-badge]: https://badge.fury.io/rb/wechat.svg
data/bin/wechat CHANGED
@@ -288,7 +288,7 @@ class App < Thor
288
288
  desc 'oauth2_url [REDIRECT_URI]', '生成OAuth2.0验证URL'
289
289
  def oauth2_url(redirect_uri)
290
290
  appid = Wechat.config.corpid || Wechat.config.appid
291
- puts oauth2_url(redirect_uri, appid)
291
+ puts wechat_api.oauth2_url(redirect_uri, appid)
292
292
  end
293
293
 
294
294
  desc 'user_update_remark [OPEN_ID, REMARK]', '设置备注名'
@@ -7,8 +7,15 @@ module Wechat
7
7
  include Cipher
8
8
 
9
9
  included do
10
- skip_before_filter :verify_authenticity_token
11
- before_filter :verify_signature, only: [:show, :create]
10
+ # Rails 5 remove before_filter and skip_before_filter
11
+ if defined?(:skip_before_action)
12
+ # Rails 5 API mode won't define verify_authenticity_token
13
+ skip_before_action :verify_authenticity_token unless defined?(:verify_authenticity_token)
14
+ before_action :verify_signature, only: [:show, :create]
15
+ else
16
+ skip_before_filter :verify_authenticity_token
17
+ before_filter :verify_signature, only: [:show, :create]
18
+ end
12
19
  end
13
20
 
14
21
  module ClassMethods
@@ -153,7 +160,7 @@ module Wechat
153
160
  response = run_responder(request)
154
161
 
155
162
  if response.respond_to? :to_xml
156
- render xml: process_response(response)
163
+ render plain: process_response(response)
157
164
  else
158
165
  render nothing: true, status: 200, content_type: 'text/html'
159
166
  end
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.6.7
4
+ version: 0.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skinnyworm
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-18 00:00:00.000000000 Z
12
+ date: 2015-12-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -18,6 +18,9 @@ dependencies:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '3.2'
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: 5.1.x
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -25,6 +28,9 @@ dependencies:
25
28
  - - ">="
26
29
  - !ruby/object:Gem::Version
27
30
  version: '3.2'
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: 5.1.x
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: nokogiri
30
36
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +110,7 @@ extra_rdoc_files: []
104
110
  files:
105
111
  - CHANGELOG.md
106
112
  - LICENSE
113
+ - README-CN.md
107
114
  - README.md
108
115
  - Rakefile
109
116
  - bin/wechat