wechat 0.7.5 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README-CN.md +11 -5
- data/README.md +9 -3
- data/bin/wechat +17 -0
- data/lib/generators/wechat/menu_generator.rb +21 -0
- data/lib/generators/wechat/templates/MENU_README +3 -0
- data/lib/generators/wechat/templates/app/controllers/wechats_controller.rb +1 -112
- data/lib/generators/wechat/templates/app/models/wechat_session.rb +1 -1
- data/lib/generators/wechat/templates/config/wechat_menu.yml +6 -0
- data/lib/generators/wechat/templates/config/wechat_menu_android.yml +15 -0
- data/lib/wechat/api.rb +15 -2
- data/lib/wechat/api_base.rb +1 -1
- data/lib/wechat/cipher.rb +1 -1
- data/lib/wechat/corp_api.rb +1 -1
- data/lib/wechat/message.rb +2 -2
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfc807dea051fded9c082a6bdbf4778433b2bbce
|
4
|
+
data.tar.gz: 55e132829fc449ed8fd9ec591ee05710386037bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4b26ce081c96d50de0e02340a6745f3cdff6334dfbdc7a521f74ee06136521ccbd42e7cf0ae2e52ba71e9dc73384e287de0c76486a95a8f0c12c4cbc3d98437
|
7
|
+
data.tar.gz: 2d6867ec622f4ae9748072eeeac18a19536579d8b74a1c56d3e59ebdf886b85a0de5dd694376fd2a0db7ca2b16542109f9eee5a6ad41d978e5dab3b903e3737a
|
data/CHANGELOG.md
CHANGED
data/README-CN.md
CHANGED
@@ -225,8 +225,11 @@ Wechat commands:
|
|
225
225
|
wechat media [MEDIA_ID, PATH] # 媒体下载
|
226
226
|
wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
|
227
227
|
wechat menu # 当前菜单
|
228
|
+
wechat menu_addconditional [CONDITIONAL_MENU_YAML_PATH] # 创建个性化菜单
|
228
229
|
wechat menu_create [MENU_YAML_PATH] # 创建菜单
|
230
|
+
wechat menu_delconditional [MENU_ID] # 删除个性化菜单
|
229
231
|
wechat menu_delete # 删除菜单
|
232
|
+
wechat menu_trymatch [USER_ID] # 测试个性化菜单匹配结果
|
230
233
|
wechat oauth2_url [REDIRECT_URI] # 生成OAuth2.0验证URL
|
231
234
|
wechat qrcode_create_limit_scene [SCENE_ID_OR_STR] # 请求永久二维码
|
232
235
|
wechat qrcode_create_scene [SCENE_ID, EXPIRE_SECONDS] # 请求临时二维码
|
@@ -326,8 +329,9 @@ $ wechat menu
|
|
326
329
|
```
|
327
330
|
|
328
331
|
##### 创建菜单
|
329
|
-
|
330
|
-
|
332
|
+
|
333
|
+
|
334
|
+
通过运行`rails g wechat:menu`可以生成一个定义菜单内容的yaml文件,菜单可以包含下列内容:
|
331
335
|
|
332
336
|
```
|
333
337
|
button:
|
@@ -363,13 +367,14 @@ button:
|
|
363
367
|
url: "http://blog.cloud-mes.com/"
|
364
368
|
```
|
365
369
|
|
366
|
-
|
370
|
+
下列命令行将上传自定义菜单:
|
367
371
|
|
368
372
|
```
|
369
373
|
$ wechat menu_create menu.yaml
|
370
|
-
|
371
374
|
```
|
372
375
|
|
376
|
+
需确保设置,权限管理中有对此应用的管理权限,否则会报[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)错。
|
377
|
+
|
373
378
|
##### 发送客服图文消息
|
374
379
|
需定义一个图文消息内容的yaml文件,比如
|
375
380
|
articles.yaml
|
@@ -572,9 +577,10 @@ end
|
|
572
577
|
- :text 响应文字消息,可以用`:with`参数来匹配文本内容 `on(:text, with:'help'){|message, content| ...}`
|
573
578
|
- :image 响应图片消息
|
574
579
|
- :voice 响应语音消息
|
580
|
+
- :shortvideo 响应短视频消息
|
575
581
|
- :video 响应视频消息
|
576
582
|
- :link 响应链接消息
|
577
|
-
- :event 响应事件消息, 可以用`:with
|
583
|
+
- :event 响应事件消息, 可以用`:with`参数来匹配事件类型,同文字消息类似,支持正则表达式匹配
|
578
584
|
- :click 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
|
579
585
|
- :view 虚拟响应事件消息, 微信传入:event,但gem内部会单独处理
|
580
586
|
- :scan 虚拟响应事件消息
|
data/README.md
CHANGED
@@ -240,8 +240,11 @@ Wechat commands:
|
|
240
240
|
wechat media [MEDIA_ID, PATH] # 媒体下载
|
241
241
|
wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
|
242
242
|
wechat menu # 当前菜单
|
243
|
+
wechat menu_addconditional [CONDITIONAL_MENU_YAML_PATH] # 创建个性化菜单
|
243
244
|
wechat menu_create [MENU_YAML_PATH] # 创建菜单
|
245
|
+
wechat menu_delconditional [MENU_ID] # 删除个性化菜单
|
244
246
|
wechat menu_delete # 删除菜单
|
247
|
+
wechat menu_trymatch [USER_ID] # 测试个性化菜单匹配结果
|
245
248
|
wechat oauth2_url [REDIRECT_URI] # 生成OAuth2.0验证URL
|
246
249
|
wechat qrcode_create_limit_scene [SCENE_ID_OR_STR] # 请求永久二维码
|
247
250
|
wechat qrcode_create_scene [SCENE_ID, EXPIRE_SECONDS] # 请求临时二维码
|
@@ -341,7 +344,7 @@ $ wechat menu
|
|
341
344
|
|
342
345
|
##### Menu create
|
343
346
|
|
344
|
-
|
347
|
+
Running command `rails g wechat:menu` to generate a menu defination yaml file:
|
345
348
|
|
346
349
|
```
|
347
350
|
button:
|
@@ -377,12 +380,14 @@ button:
|
|
377
380
|
url: "http://blog.cloud-mes.com/"
|
378
381
|
```
|
379
382
|
|
380
|
-
|
383
|
+
Running below command to upload the menu:
|
381
384
|
|
382
385
|
```
|
383
386
|
$ wechat menu_create menu.yaml
|
384
387
|
```
|
385
388
|
|
389
|
+
Caution: make sure you having management privilege for those application, otherwise 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.
|
390
|
+
|
386
391
|
##### Sent custom news
|
387
392
|
|
388
393
|
|
@@ -586,9 +591,10 @@ Below is current supported message_type:
|
|
586
591
|
- :text text message, using `:with` to match text content like `on(:text, with:'help'){|message, content| ...}`
|
587
592
|
- :image image message
|
588
593
|
- :voice voice message
|
594
|
+
- :shortvideo shortvideo message
|
589
595
|
- :video video message
|
590
596
|
- :link link message
|
591
|
-
- :event event message, using `:with` to match particular event
|
597
|
+
- :event event message, using `:with` to match particular event, support regular expression match similr to text message.
|
592
598
|
- :click virtual event message, wechat still sent event message,but gems will mapping to menu click event.
|
593
599
|
- :view virtual view message, wechat still sent event message,but gems will mapping to menu view page event.
|
594
600
|
- :scan virtual scan message, wechat still sent event message, but gems will mapping on scan event
|
data/bin/wechat
CHANGED
@@ -320,6 +320,23 @@ class App < Thor
|
|
320
320
|
puts 'Menu created' if wechat_api.menu_create(menu)
|
321
321
|
end
|
322
322
|
|
323
|
+
desc 'menu_addconditional [CONDITIONAL_MENU_YAML_PATH]', '创建个性化菜单'
|
324
|
+
def menu_addconditional(conditional_menu_yaml_path)
|
325
|
+
conditional_menu = YAML.load(File.read(conditional_menu_yaml_path))
|
326
|
+
add_result = wechat_api.menu_addconditional(conditional_menu)
|
327
|
+
puts "Conditional menu created: #{add_result}" if add_result
|
328
|
+
end
|
329
|
+
|
330
|
+
desc 'menu_trymatch [USER_ID]', '测试个性化菜单匹配结果'
|
331
|
+
def menu_trymatch(user_id)
|
332
|
+
puts wechat_api.menu_trymatch(user_id)
|
333
|
+
end
|
334
|
+
|
335
|
+
desc 'menu_delconditional [MENU_ID]', '删除个性化菜单'
|
336
|
+
def menu_delconditional(menuid)
|
337
|
+
puts wechat_api.menu_delconditional(menuid)
|
338
|
+
end
|
339
|
+
|
323
340
|
desc 'media [MEDIA_ID, PATH]', '媒体下载'
|
324
341
|
def media(media_id, path)
|
325
342
|
tmp_file = wechat_api.media(media_id)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Wechat
|
2
|
+
module Generators
|
3
|
+
class MenuGenerator < Rails::Generators::Base
|
4
|
+
desc 'Generate wechat menu'
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
class_option :conditional, desc: 'Generate conditional menu', type: :boolean, default: false
|
7
|
+
|
8
|
+
def copy_menu
|
9
|
+
if options.conditional?
|
10
|
+
template 'config/wechat_menu_android.yml'
|
11
|
+
else
|
12
|
+
template 'config/wechat_menu.yml'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_readme
|
17
|
+
readme 'MENU_README' if behavior == :invoke
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -3,121 +3,10 @@ class WechatsController < ApplicationController
|
|
3
3
|
<% else -%>
|
4
4
|
class WechatsController < ActionController::Base
|
5
5
|
<% end -%>
|
6
|
+
# For details on the DSL available within this file, see https://github.com/Eric-Guo/wechat#rails-responder-controller-dsl
|
6
7
|
wechat_responder
|
7
8
|
|
8
|
-
# default text responder when no other match
|
9
9
|
on :text do |request, content|
|
10
10
|
request.reply.text "echo: #{content}" # Just echo
|
11
11
|
end
|
12
|
-
|
13
|
-
# When receive 'help', will trigger this responder
|
14
|
-
on :text, with: 'help' do |request|
|
15
|
-
request.reply.text 'help content'
|
16
|
-
end
|
17
|
-
|
18
|
-
# When receive '<n>news', will match and will got count as <n> as parameter
|
19
|
-
on :text, with: /^(\d+) news$/ do |request, count|
|
20
|
-
# Wechat article can only contain max 10 items, large than 10 will dropped.
|
21
|
-
news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: 'News title', content: "No. #{n} news content" } }
|
22
|
-
request.reply.news(news) do |article, n, index| # article is return object
|
23
|
-
article.item title: "#{index} #{n[:title]}", description: n[:content], pic_url: 'http://www.baidu.com/img/bdlogo.gif', url: 'http://www.baidu.com/'
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
on :event, with: 'subscribe' do |request|
|
28
|
-
request.reply.text "#{request[:FromUserName]} subscribe now"
|
29
|
-
end
|
30
|
-
|
31
|
-
# When unsubscribe user scan qrcode qrscene_xxxxxx to subscribe in public account
|
32
|
-
# notice user will subscribe public account at same time, so wechat won't trigger subscribe event any more
|
33
|
-
on :scan, with: 'qrscene_xxxxxx' do |request, ticket|
|
34
|
-
request.reply.text "Unsubscribe user #{request[:FromUserName]} Ticket #{ticket}"
|
35
|
-
end
|
36
|
-
|
37
|
-
# When subscribe user scan scene_id in public account
|
38
|
-
on :scan, with: 'scene_id' do |request, ticket|
|
39
|
-
request.reply.text "Subscribe user #{request[:FromUserName]} Ticket #{ticket}"
|
40
|
-
end
|
41
|
-
|
42
|
-
# When no any on :scan responder can match subscribe user scaned scene_id
|
43
|
-
on :event, with: 'scan' do |request|
|
44
|
-
if request[:EventKey].present?
|
45
|
-
request.reply.text "event scan got EventKey #{request[:EventKey]} Ticket #{request[:Ticket]}"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# When enterprise user press menu BINDING_QR_CODE and success to scan bar code
|
50
|
-
on :scan, with: 'BINDING_QR_CODE' do |request, scan_result, scan_type|
|
51
|
-
request.reply.text "User #{request[:FromUserName]} ScanResult #{scan_result} ScanType #{scan_type}"
|
52
|
-
end
|
53
|
-
|
54
|
-
# Except QR code, wechat can also scan CODE_39 bar code in enterprise account
|
55
|
-
on :scan, with: 'BINDING_BARCODE' do |message, scan_result|
|
56
|
-
if scan_result.start_with? 'CODE_39,'
|
57
|
-
message.reply.text "User: #{message[:FromUserName]} scan barcode, result is #{scan_result.split(',')[1]}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# When user click the menu button
|
62
|
-
on :click, with: 'BOOK_LUNCH' do |request, key|
|
63
|
-
request.reply.text "User: #{request[:FromUserName]} click #{key}"
|
64
|
-
end
|
65
|
-
|
66
|
-
# When user view URL in the menu button
|
67
|
-
on :view, with: 'http://wechat.somewhere.com/view_url' do |request, view|
|
68
|
-
request.reply.text "#{request[:FromUserName]} view #{view}"
|
69
|
-
end
|
70
|
-
|
71
|
-
# When user sent the imsage
|
72
|
-
on :image do |request|
|
73
|
-
request.reply.image(request[:MediaId]) # Echo the sent image to user
|
74
|
-
end
|
75
|
-
|
76
|
-
# When user sent the voice
|
77
|
-
on :voice do |request|
|
78
|
-
request.reply.voice(request[:MediaId]) # Echo the sent voice to user
|
79
|
-
end
|
80
|
-
|
81
|
-
# When user sent the video
|
82
|
-
on :video do |request|
|
83
|
-
nickname = wechat.user(request[:FromUserName])['nickname'] # Call wechat api to get sender nickname
|
84
|
-
request.reply.video(request[:MediaId], title: 'Echo', description: "Got #{nickname} sent video") # Echo the sent video to user
|
85
|
-
end
|
86
|
-
|
87
|
-
# When user sent location
|
88
|
-
on :location do |request|
|
89
|
-
request.reply.text("Latitude: #{message[:Latitude]} Longitude: #{message[:Longitude]} Precision: #{message[:Precision]}")
|
90
|
-
end
|
91
|
-
|
92
|
-
on :event, with: 'unsubscribe' do |request|
|
93
|
-
request.reply.success # user can not receive this message
|
94
|
-
end
|
95
|
-
|
96
|
-
# When user enter the app / agent app
|
97
|
-
on :event, with: 'enter_agent' do |request|
|
98
|
-
request.reply.text "#{request[:FromUserName]} enter agent app now"
|
99
|
-
end
|
100
|
-
|
101
|
-
# When batch job create/update user (incremental) finished.
|
102
|
-
on :batch_job, with: 'sync_user' do |request, batch_job|
|
103
|
-
request.reply.text "sync_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
104
|
-
end
|
105
|
-
|
106
|
-
# When batch job replace user (full sync) finished.
|
107
|
-
on :batch_job, with: 'replace_user' do |request, batch_job|
|
108
|
-
request.reply.text "replace_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
109
|
-
end
|
110
|
-
|
111
|
-
# When batch job invent user finished.
|
112
|
-
on :batch_job, with: 'invite_user' do |request, batch_job|
|
113
|
-
request.reply.text "invite_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
114
|
-
end
|
115
|
-
|
116
|
-
# When batch job replace department (full sync) finished.
|
117
|
-
on :batch_job, with: 'replace_party' do |request, batch_job|
|
118
|
-
request.reply.text "replace_party job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
119
|
-
end
|
120
|
-
|
121
|
-
# Any not match above will fail to below
|
122
|
-
on :fallback, respond: 'fallback message'
|
123
12
|
end
|
@@ -10,7 +10,7 @@ class WechatSession < ActiveRecord::Base
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# called by wechat gems after response Techent server at controller#create
|
13
|
-
def save_session(
|
13
|
+
def save_session(_response_message)
|
14
14
|
touch unless new_record? # Always refresh updated_at even no change
|
15
15
|
save!
|
16
16
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
button:
|
2
|
+
-
|
3
|
+
type: "view"
|
4
|
+
name: "Testing Android"
|
5
|
+
url: "http://xxxxx.proxy.qqbrowser.cc"
|
6
|
+
|
7
|
+
# More match rule see http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
|
8
|
+
matchrule:
|
9
|
+
# group_id: 2
|
10
|
+
# sex: 1
|
11
|
+
# country: 中国
|
12
|
+
# province: 上海
|
13
|
+
# city: 杨浦
|
14
|
+
client_platform_type: 1
|
15
|
+
# language: zh_CN
|
data/lib/wechat/api.rb
CHANGED
@@ -5,8 +5,8 @@ require 'wechat/ticket/public_jsapi_ticket'
|
|
5
5
|
|
6
6
|
module Wechat
|
7
7
|
class Api < ApiBase
|
8
|
-
API_BASE = 'https://api.weixin.qq.com/cgi-bin/'
|
9
|
-
OAUTH2_BASE = 'https://api.weixin.qq.com/sns/oauth2/'
|
8
|
+
API_BASE = 'https://api.weixin.qq.com/cgi-bin/'.freeze
|
9
|
+
OAUTH2_BASE = 'https://api.weixin.qq.com/sns/oauth2/'.freeze
|
10
10
|
|
11
11
|
def initialize(appid, secret, token_file, timeout, skip_verify_ssl, jsapi_ticket_file)
|
12
12
|
@client = Client.new(API_BASE, timeout, skip_verify_ssl)
|
@@ -85,6 +85,19 @@ module Wechat
|
|
85
85
|
post 'menu/create', JSON.generate(menu)
|
86
86
|
end
|
87
87
|
|
88
|
+
def menu_addconditional(menu)
|
89
|
+
# Wechat not accept 7bit escaped json(eg \uxxxx), must using UTF-8, possible security vulnerability?
|
90
|
+
post 'menu/addconditional', JSON.generate(menu)
|
91
|
+
end
|
92
|
+
|
93
|
+
def menu_trymatch(user_id)
|
94
|
+
post 'menu/trymatch', JSON.generate(user_id: user_id)
|
95
|
+
end
|
96
|
+
|
97
|
+
def menu_delconditional(menuid)
|
98
|
+
post 'menu/delconditional', JSON.generate(menuid: menuid)
|
99
|
+
end
|
100
|
+
|
88
101
|
def material(media_id)
|
89
102
|
get 'material/get', params: { media_id: media_id }, as: :file
|
90
103
|
end
|
data/lib/wechat/api_base.rb
CHANGED
data/lib/wechat/cipher.rb
CHANGED
data/lib/wechat/corp_api.rb
CHANGED
@@ -8,7 +8,7 @@ module Wechat
|
|
8
8
|
class CorpApi < ApiBase
|
9
9
|
attr_reader :agentid
|
10
10
|
|
11
|
-
API_BASE = 'https://qyapi.weixin.qq.com/cgi-bin/'
|
11
|
+
API_BASE = 'https://qyapi.weixin.qq.com/cgi-bin/'.freeze
|
12
12
|
|
13
13
|
def initialize(appid, secret, token_file, agentid, timeout, skip_verify_ssl, jsapi_ticket_file)
|
14
14
|
@client = Client.new(API_BASE, timeout, skip_verify_ssl)
|
data/lib/wechat/message.rb
CHANGED
@@ -143,9 +143,9 @@ module Wechat
|
|
143
143
|
'MediaId' => 'media_id',
|
144
144
|
'ThumbMediaId' => 'thumb_media_id',
|
145
145
|
'TemplateId' => 'template_id'
|
146
|
-
}
|
146
|
+
}.freeze
|
147
147
|
|
148
|
-
TO_JSON_ALLOWED = %w(touser msgtype content image voice video music news articles template agentid)
|
148
|
+
TO_JSON_ALLOWED = %w(touser msgtype content image voice video music news articles template agentid).freeze
|
149
149
|
|
150
150
|
def to_json
|
151
151
|
json_hash = deep_recursive(message_hash) do |key, value|
|
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.7.
|
4
|
+
version: 0.7.6
|
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: 2016-
|
12
|
+
date: 2016-03-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -136,12 +136,16 @@ files:
|
|
136
136
|
- bin/wechat
|
137
137
|
- lib/action_controller/wechat_responder.rb
|
138
138
|
- lib/generators/wechat/install_generator.rb
|
139
|
+
- lib/generators/wechat/menu_generator.rb
|
139
140
|
- lib/generators/wechat/redis_store_generator.rb
|
140
141
|
- lib/generators/wechat/session_generator.rb
|
142
|
+
- lib/generators/wechat/templates/MENU_README
|
141
143
|
- lib/generators/wechat/templates/app/controllers/wechats_controller.rb
|
142
144
|
- lib/generators/wechat/templates/app/models/wechat_session.rb
|
143
145
|
- lib/generators/wechat/templates/config/initializers/wechat_redis_store.rb
|
144
146
|
- lib/generators/wechat/templates/config/wechat.yml
|
147
|
+
- lib/generators/wechat/templates/config/wechat_menu.yml
|
148
|
+
- lib/generators/wechat/templates/config/wechat_menu_android.yml
|
145
149
|
- lib/generators/wechat/templates/db/migration.rb
|
146
150
|
- lib/wechat.rb
|
147
151
|
- lib/wechat/api.rb
|