wechat 0.4.2 → 0.5.0
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +76 -27
- data/bin/wechat +174 -7
- data/lib/generators/wechat/install_generator.rb +20 -0
- data/lib/generators/wechat/templates/app/controllers/wechats_controller.rb +91 -0
- data/lib/generators/wechat/templates/config/wechat.yml +27 -0
- data/lib/wechat/api.rb +30 -5
- data/lib/wechat/api_base.rb +9 -1
- data/lib/wechat/corp_api.rb +75 -7
- data/lib/wechat/responder.rb +13 -8
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26688ce4d31dd3c7df24fce05a5c722f255251a8
|
4
|
+
data.tar.gz: 8c504cbd4bd2b95eeadbafc51d99771777a6e23b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7505d3220b2a8adfcd2b8883bdbbc76d2ed1ef65893e88e73deaf05219e484ade74d5822b6b8a10dcd0e26cb9b9f46ad0bb37a2acad4635ce9d53bd21c3080e3
|
7
|
+
data.tar.gz: acfe7dae6763e066bdceef9d97f5d91ea517ab33b3213f7b0278fba847def719b0df768eb967879e06119ae8e891910f00ec3c6a49b63ecf93fc458892210a34
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v0.5.0 (released at 9/25/2015)
|
4
|
+
|
5
|
+
* Only relay on activesupport on run time, so will greatly improve wechat cli startup time
|
6
|
+
* Add rails generator support `rails g wechat:install`
|
7
|
+
* Add batch job support for enterprise account like batch create user/department, both API, callback responder and CLI
|
8
|
+
* Add material management API and CLI
|
9
|
+
* Add tag API and CLI for enterprise account
|
10
|
+
* Add QR code scene function for public account
|
11
|
+
|
3
12
|
## v0.4.2 (released at 9/7/2015)
|
4
13
|
|
5
14
|
* Fix wrong number of arguments at Wechat::Responder.on by using arity #47
|
data/README.md
CHANGED
@@ -28,6 +28,20 @@ Or add to your app's `Gemfile`:
|
|
28
28
|
gem 'wechat'
|
29
29
|
```
|
30
30
|
|
31
|
+
Run the following command to install it:
|
32
|
+
|
33
|
+
```console
|
34
|
+
bundle install
|
35
|
+
```
|
36
|
+
|
37
|
+
Run the generator:
|
38
|
+
|
39
|
+
```console
|
40
|
+
rails generate wechat:install
|
41
|
+
```
|
42
|
+
|
43
|
+
运行`rails g wechat:install`后会自动生成wechat.yml配置,还有wechat controller及相关路由配置到当前Rails项目。
|
44
|
+
|
31
45
|
|
32
46
|
## 配置
|
33
47
|
|
@@ -46,7 +60,7 @@ Windows或者使用企业号,需要存放在`C:/Users/[user_name]/`下,其
|
|
46
60
|
```
|
47
61
|
corpid: "my_appid"
|
48
62
|
corpsecret: "my_secret"
|
49
|
-
agentid:
|
63
|
+
agentid: 1 # 企业应用的id,整型。可在应用的设置页面查看
|
50
64
|
access_token: "C:/Users/[user_name]/wechat_access_token"
|
51
65
|
```
|
52
66
|
|
@@ -81,7 +95,7 @@ test:
|
|
81
95
|
default: &default
|
82
96
|
corpid: "corpid"
|
83
97
|
corpsecret: "corpsecret"
|
84
|
-
agentid:
|
98
|
+
agentid: 1
|
85
99
|
access_token: "C:/Users/[user_name]/wechat_access_token"
|
86
100
|
token: ""
|
87
101
|
encoding_aes_key: ""
|
@@ -108,7 +122,7 @@ test:
|
|
108
122
|
|
109
123
|
##### 配置跳过SSL认证
|
110
124
|
|
111
|
-
Wechat服务器有报道曾出现[RestClient::SSLCertificateNotVerified](http://qydev.weixin.qq.com/qa/index.php?qa=11037)错误,此时可以选择关闭SSL
|
125
|
+
Wechat服务器有报道曾出现[RestClient::SSLCertificateNotVerified](http://qydev.weixin.qq.com/qa/index.php?qa=11037)错误,此时可以选择关闭SSL验证。`skip_verify_ssl: true`
|
112
126
|
|
113
127
|
#### 为每个Responder配置不同的appid和secret
|
114
128
|
|
@@ -139,6 +153,12 @@ wechat gems 内部不会检查权限。但因公众号类型不同,和微信
|
|
139
153
|
```
|
140
154
|
$ wechat
|
141
155
|
Wechat commands:
|
156
|
+
wechat agent [AGENT_ID] # 获取企业号应用详情
|
157
|
+
wechat agent_list # 获取应用概况列表
|
158
|
+
wechat batch_job_result [JOB_ID] # 获取异步任务结果
|
159
|
+
wechat batch_replaceparty [BATCH_PARTY_CSV_MEDIA_ID] # 全量覆盖部门
|
160
|
+
wechat batch_replaceuser [BATCH_USER_CSV_MEDIA_ID] # 全量覆盖成员
|
161
|
+
wechat batch_syncuser [SYNC_USER_CSV_MEDIA_ID] # 增量更新成员
|
142
162
|
wechat callbackip # 获取微信服务器IP地址
|
143
163
|
wechat custom_image [OPENID, IMAGE_PATH] # 发送图片客服消息
|
144
164
|
wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # 发送音乐客服消息
|
@@ -148,6 +168,7 @@ Wechat commands:
|
|
148
168
|
wechat custom_voice [OPENID, VOICE_PATH] # 发送语音客服消息
|
149
169
|
wechat department [DEPARTMENT_ID] # 获取部门列表
|
150
170
|
wechat department_create [NAME, PARENT_ID] # 创建部门
|
171
|
+
wechat department_delete [DEPARTMENT_ID] # 删除部门
|
151
172
|
wechat group_create [GROUP_NAME] # 创建分组
|
152
173
|
wechat group_delete [GROUP_ID] # 删除分组
|
153
174
|
wechat group_update [GROUP_ID, NEW_GROUP_NAME] # 修改分组名
|
@@ -155,19 +176,35 @@ Wechat commands:
|
|
155
176
|
wechat invite_user [USER_ID] # 邀请成员关注
|
156
177
|
wechat material [MEDIA_ID, PATH] # 永久媒体下载
|
157
178
|
wechat material_add [MEDIA_TYPE, PATH] # 永久媒体上传
|
158
|
-
wechat material_count #
|
179
|
+
wechat material_count # 获取永久素材总数
|
159
180
|
wechat material_delete [MEDIA_ID] # 删除永久素材
|
181
|
+
wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
|
160
182
|
wechat media [MEDIA_ID, PATH] # 媒体下载
|
161
183
|
wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
|
162
184
|
wechat menu # 当前菜单
|
163
185
|
wechat menu_create [MENU_YAML_PATH] # 创建菜单
|
164
186
|
wechat menu_delete # 删除菜单
|
165
187
|
wechat message_send [OPENID, TEXT_MESSAGE] # 发送文字消息(仅企业号)
|
188
|
+
wechat qrcode_create_limit_scene [SCENE_ID_OR_STR] # 请求永久二维码
|
189
|
+
wechat qrcode_create_scene [SCENE_ID, EXPIRE_SECONDS] # 请求临时二维码
|
190
|
+
wechat qrcode_download [TICKET, QR_CODE_PIC_PATH] # 通过ticket下载二维码
|
191
|
+
wechat tag [TAG_ID] # 获取标签成员
|
192
|
+
wechat tag_add_department [TAG_ID, PARTY_IDS] # 增加标签部门
|
193
|
+
wechat tag_add_user [TAG_ID, USER_IDS] # 增加标签成员
|
194
|
+
wechat tag_create [TAGNAME, TAG_ID] # 创建标签
|
195
|
+
wechat tag_del_user [TAG_ID, USER_IDS] # 删除标签成员
|
196
|
+
wechat tag_del_department [TAG_ID, PARTY_IDS] # 删除标签部门
|
197
|
+
wechat tag_delete [TAG_ID] # 删除标签
|
198
|
+
wechat tag_update [TAG_ID, TAGNAME] # 更新标签名字
|
199
|
+
wechat tags # 获取标签列表
|
166
200
|
wechat template_message [OPENID, TEMPLATE_YAML_PATH] # 模板消息接口
|
167
201
|
wechat user [OPEN_ID] # 获取用户基本信息
|
168
202
|
wechat user_change_group [OPEN_ID, TO_GROUP_ID] # 移动用户分组
|
169
203
|
wechat user_delete [USER_ID] # 删除成员
|
170
204
|
wechat user_group [OPEN_ID] # 查询用户所在分组
|
205
|
+
wechat user_list [DEPARTMENT_ID] # 获取部门成员详情
|
206
|
+
wechat user_simplelist [DEPARTMENT_ID] # 获取部门成员
|
207
|
+
wechat user_update_remark [OPEN_ID, REMARK] # 设置备注名
|
171
208
|
wechat users # 关注者列表
|
172
209
|
```
|
173
210
|
|
@@ -221,20 +258,14 @@ button:
|
|
221
258
|
type: "scancode_waitmsg"
|
222
259
|
name: "绑定用餐二维码"
|
223
260
|
key: "BINDING_QR_CODE"
|
224
|
-
sub_button:
|
225
|
-
-
|
226
261
|
-
|
227
262
|
type: "click"
|
228
263
|
name: "预订午餐"
|
229
264
|
key: "BOOK_LUNCH"
|
230
|
-
sub_button:
|
231
|
-
-
|
232
265
|
-
|
233
266
|
type: "click"
|
234
267
|
name: "预订晚餐"
|
235
268
|
key: "BOOK_DINNER"
|
236
|
-
sub_button:
|
237
|
-
-
|
238
269
|
-
|
239
270
|
name: "查询"
|
240
271
|
sub_button:
|
@@ -242,19 +273,14 @@ button:
|
|
242
273
|
type: "click"
|
243
274
|
name: "进出记录"
|
244
275
|
key: "BADGE_IN_OUT"
|
245
|
-
sub_button:
|
246
|
-
-
|
247
276
|
-
|
248
277
|
type: "click"
|
249
278
|
name: "年假余额"
|
250
279
|
key: "ANNUAL_LEAVE"
|
251
|
-
sub_button:
|
252
|
-
-
|
253
280
|
-
|
254
281
|
type: "view"
|
255
282
|
name: "关于"
|
256
283
|
url: "http://blog.cloud-mes.com/"
|
257
|
-
|
258
284
|
```
|
259
285
|
|
260
286
|
然后执行命令行,需确保设置,权限管理中有对此应用的管理权限,否则会报[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)错。
|
@@ -316,7 +342,6 @@ template:
|
|
316
342
|
|
317
343
|
```
|
318
344
|
$ wechat template_message oCfEht9oM*********** template.yml
|
319
|
-
|
320
345
|
```
|
321
346
|
|
322
347
|
## Rails Responder Controller DSL
|
@@ -325,7 +350,6 @@ $ wechat template_message oCfEht9oM*********** template.yml
|
|
325
350
|
|
326
351
|
```ruby
|
327
352
|
resource :wechat, only:[:show, :create]
|
328
|
-
|
329
353
|
```
|
330
354
|
|
331
355
|
然后创建Controller class, 例如
|
@@ -340,16 +364,16 @@ class WechatsController < ApplicationController
|
|
340
364
|
end
|
341
365
|
|
342
366
|
# 当请求的文字信息内容为'help'时, 使用这个responder处理
|
343
|
-
on :text, with:
|
344
|
-
request.reply.text
|
367
|
+
on :text, with: 'help' do |request|
|
368
|
+
request.reply.text 'help content' #回复帮助信息
|
345
369
|
end
|
346
370
|
|
347
371
|
# 当请求的文字信息内容为'<n>条新闻'时, 使用这个responder处理, 并将n作为第二个参数
|
348
372
|
on :text, with: /^(\d+)条新闻$/ do |request, count|
|
349
373
|
# 微信最多显示10条新闻,大于10条将只取前10条
|
350
|
-
news = (1..count.to_i).each_with_object([]) { |n, memo| memo << {title:
|
374
|
+
news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: '新闻标题', content: "第#{n}条新闻的内容#{n.hash}" } }
|
351
375
|
request.reply.news(news) do |article, n, index| # 回复"articles"
|
352
|
-
article.item title: "#{index} #{n[:title]}", description: n[:content], pic_url:
|
376
|
+
article.item title: "#{index} #{n[:title]}", description: n[:content], pic_url: 'http://www.baidu.com/img/bdlogo.gif', url: 'http://www.baidu.com/'
|
353
377
|
end
|
354
378
|
end
|
355
379
|
|
@@ -377,8 +401,8 @@ class WechatsController < ApplicationController
|
|
377
401
|
|
378
402
|
# 处理视频信息
|
379
403
|
on :video do |request|
|
380
|
-
nickname = wechat.user(request[:FromUserName])[
|
381
|
-
request.reply.video(request[:MediaId], title:
|
404
|
+
nickname = wechat.user(request[:FromUserName])['nickname'] #调用 api 获得发送者的nickname
|
405
|
+
request.reply.video(request[:MediaId], title: '回声', description: "#{nickname}发来的视频请求") #直接视频返回给用户
|
382
406
|
end
|
383
407
|
|
384
408
|
# 处理地理位置信息
|
@@ -393,13 +417,37 @@ class WechatsController < ApplicationController
|
|
393
417
|
|
394
418
|
# 当用户取消关注订阅
|
395
419
|
on :event, with: 'unsubscribe' do |request|
|
396
|
-
request.reply.text "#{request[:FromUserName]}
|
420
|
+
request.reply.text "#{request[:FromUserName]} can not receive this message"
|
421
|
+
end
|
422
|
+
|
423
|
+
# 成员进入应用的事件推送
|
424
|
+
on :event, with: 'enter_agent' do |request|
|
425
|
+
request.reply.text "#{request[:FromUserName]} enter agent app now"
|
426
|
+
end
|
427
|
+
|
428
|
+
# 当异步任务增量更新成员完成时推送
|
429
|
+
on :event, with: 'sync_user' do |request, batch_job|
|
430
|
+
request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
431
|
+
end
|
432
|
+
|
433
|
+
# 当异步任务全量覆盖成员完成时推送
|
434
|
+
on :event, with: 'replace_user' do |request, batch_job|
|
435
|
+
request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
436
|
+
end
|
437
|
+
|
438
|
+
# 当异步任务邀请成员关注完成时推送
|
439
|
+
on :event, with: 'invite_user' do |request, batch_job|
|
440
|
+
request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
441
|
+
end
|
442
|
+
|
443
|
+
# 当异步任务全量覆盖部门完成时推送
|
444
|
+
on :event, with: 'replace_party' do |request, batch_job|
|
445
|
+
request.reply.text "job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
397
446
|
end
|
398
447
|
|
399
448
|
# 当无任何responder处理用户信息时,使用这个responder处理
|
400
|
-
on :fallback, respond:
|
449
|
+
on :fallback, respond: 'fallback message'
|
401
450
|
end
|
402
|
-
|
403
451
|
```
|
404
452
|
|
405
453
|
在controller中使用`wechat_responder`引入Responder DSL, 之后可以用
|
@@ -444,4 +492,5 @@ Wechat 的核心是一个Message DSL,帮助开发者构建各种类型的消息
|
|
444
492
|
|
445
493
|
## 已知问题
|
446
494
|
|
447
|
-
企业号接受菜单消息时,Wechat腾讯服务器无法解析部分域名,请使用IP绑定回调URL,用户的普通消息目前不受影响。
|
495
|
+
* 企业号接受菜单消息时,Wechat腾讯服务器无法解析部分域名,请使用IP绑定回调URL,用户的普通消息目前不受影响。
|
496
|
+
* 企业号全量覆盖成员使用的csv通讯录格式,直接将下载的模板导入[是不工作的](http://qydev.weixin.qq.com/qa/index.php?qa=13978),必须使用Excel打开,然后另存为csv格式才会变成合法格式。
|
data/bin/wechat
CHANGED
@@ -45,7 +45,7 @@ HELP
|
|
45
45
|
home_config_file = File.join(Dir.home, '.wechat.yml')
|
46
46
|
|
47
47
|
if File.exist?(rails_config_file)
|
48
|
-
config = YAML.load(ERB.new(File.
|
48
|
+
config = YAML.load(ERB.new(File.read(rails_config_file)).result)['default']
|
49
49
|
if config.present? && (config['appid'] || config['corpid'])
|
50
50
|
puts 'Using rails project config/wechat.yml default setting...'
|
51
51
|
else
|
@@ -68,6 +68,13 @@ HELP
|
|
68
68
|
puts Helper.with(options).callbackip
|
69
69
|
end
|
70
70
|
|
71
|
+
desc 'qrcode_download [TICKET, QR_CODE_PIC_PATH]', '通过ticket下载二维码'
|
72
|
+
def qrcode_download(ticket, qr_code_pic_path)
|
73
|
+
tmp_file = Helper.with(options).qrcode(ticket)
|
74
|
+
FileUtils.mv(tmp_file.path, qr_code_pic_path)
|
75
|
+
puts 'File downloaded'
|
76
|
+
end
|
77
|
+
|
71
78
|
desc 'groups', '所有用户分组列表'
|
72
79
|
def groups
|
73
80
|
puts Helper.with(options).groups
|
@@ -95,9 +102,121 @@ HELP
|
|
95
102
|
puts Helper.with(options).department_create(name, api_opts[:parentid] || '1')
|
96
103
|
end
|
97
104
|
|
105
|
+
desc 'department_delete [DEPARTMENT_ID]', '删除部门'
|
106
|
+
def department_delete(departmentid)
|
107
|
+
puts Helper.with(options).department_delete(departmentid)
|
108
|
+
end
|
109
|
+
|
98
110
|
desc 'department [DEPARTMENT_ID]', '获取部门列表'
|
99
|
-
def department(departmentid)
|
100
|
-
|
111
|
+
def department(departmentid = 0)
|
112
|
+
r = Helper.with(options).department(departmentid)
|
113
|
+
puts "errcode: #{r['errcode']} errmsg: #{r['errmsg']}"
|
114
|
+
puts 'Or# pid id name'
|
115
|
+
r['department'].sort_by { |d| d['order'].to_i + d['parentid'].to_i * 1000 } .each do |i|
|
116
|
+
puts format('%3d %3d %3d %s', i['order'], i['parentid'], i['id'], i['name'])
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
desc 'user_simplelist [DEPARTMENT_ID]', '获取部门成员'
|
121
|
+
method_option :fetch_child, aliases: '-c', desc: '是否递归获取子部门下面的成员', default: 1
|
122
|
+
method_option :status, aliases: '-s', desc: '0 获取全部成员,1 获取已关注成员列表,2 获取禁用成员列表,4 获取未关注成员列表。status可叠加', default: 0
|
123
|
+
def user_simplelist(departmentid = 0)
|
124
|
+
api_opts = options.slice(:fetch_child, :status)
|
125
|
+
|
126
|
+
r = Helper.with(options).user_simplelist(departmentid, api_opts[:fetch_child], api_opts[:status])
|
127
|
+
puts "errcode: #{r['errcode']} errmsg: #{r['errmsg']}"
|
128
|
+
puts " userid Name #{' ' * 20} department_ids"
|
129
|
+
r['userlist'].sort_by { |d| d['userid'] } .each do |i|
|
130
|
+
puts format('%7s %-25s %-14s', i['userid'], i['name'], i['department'])
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
desc 'user_list [DEPARTMENT_ID]', '获取部门成员详情'
|
135
|
+
method_option :fetch_child, aliases: '-c', desc: '是否递归获取子部门下面的成员', default: 0
|
136
|
+
method_option :status, aliases: '-s', desc: '0 获取全部成员,1 获取已关注成员列表,2 获取禁用成员列表,4 获取未关注成员列表。status可叠加', default: 0
|
137
|
+
def user_list(departmentid = 0)
|
138
|
+
api_opts = options.slice(:fetch_child, :status)
|
139
|
+
|
140
|
+
r = Helper.with(options).user_list(departmentid, api_opts[:fetch_child], api_opts[:status])
|
141
|
+
puts "errcode: #{r['errcode']} errmsg: #{r['errmsg']}"
|
142
|
+
puts " userid Name #{' ' * 15} department_ids position mobile #{' ' * 5}gender email #{' ' * 10}weixinid status extattr"
|
143
|
+
r['userlist'].sort_by { |d| d['userid'] } .each do |i|
|
144
|
+
puts format('%7s %-20s %-14s %-8s %-11s %-6s %-15s %-15s %-6s %s',
|
145
|
+
i['userid'], i['name'], i['department'], i['position'], i['mobile'],
|
146
|
+
i['gender'], i['email'], i['weixinid'], i['status'], i['extattr'])
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
desc 'tag_create [TAGNAME, TAG_ID]', '创建标签'
|
151
|
+
method_option :tagid, aliases: '-id', desc: '整型,指定此参数时新增的标签会生成对应的标签id,不指定时则以目前最大的id自增'
|
152
|
+
def tag_create(name)
|
153
|
+
api_opts = options.slice(:tagid)
|
154
|
+
puts Helper.with(options).tag_create(name, api_opts[:tagid])
|
155
|
+
end
|
156
|
+
|
157
|
+
desc 'tag_update [TAG_ID, TAGNAME]', '更新标签名字'
|
158
|
+
def tag_update(tagid, tagname)
|
159
|
+
puts Helper.with(options).tag_update(tagid, tagname)
|
160
|
+
end
|
161
|
+
|
162
|
+
desc 'tag_delete [TAG_ID]', '删除标签'
|
163
|
+
def tag_delete(tagid)
|
164
|
+
puts Helper.with(options).tag_delete(tagid)
|
165
|
+
end
|
166
|
+
|
167
|
+
desc 'tags', '获取标签列表'
|
168
|
+
def tags
|
169
|
+
puts Helper.with(options).tags
|
170
|
+
end
|
171
|
+
|
172
|
+
desc 'tag [TAG_ID]', '获取标签成员'
|
173
|
+
def tag(tagid)
|
174
|
+
puts Helper.with(options).tag(tagid)
|
175
|
+
end
|
176
|
+
|
177
|
+
desc 'tag_add_user [TAG_ID, USER_IDS]', '增加标签成员'
|
178
|
+
def tag_add_user(tagid, userids)
|
179
|
+
puts Helper.with(options).tag_add_user(tagid, userids.split(','))
|
180
|
+
end
|
181
|
+
|
182
|
+
desc 'tag_add_department [TAG_ID, PARTY_IDS]', '增加标签部门'
|
183
|
+
def tag_add_department(tagid, partyids)
|
184
|
+
puts Helper.with(options).tag_add_user(tagid, nil, partyids.split(','))
|
185
|
+
end
|
186
|
+
|
187
|
+
desc 'tag_del_user [TAG_ID, USER_IDS]', '删除标签成员'
|
188
|
+
def tag_del_user(tagid, userids)
|
189
|
+
puts Helper.with(options).tag_del_user(tagid, userids.split(','))
|
190
|
+
end
|
191
|
+
|
192
|
+
desc 'tag_del_department [TAG_ID, PARTY_IDS]', '删除标签部门'
|
193
|
+
def tag_del_department(tagid, partyids)
|
194
|
+
puts Helper.with(options).tag_del_user(tagid, nil, partyids.split(','))
|
195
|
+
end
|
196
|
+
|
197
|
+
desc 'agent_list', '获取应用概况列表'
|
198
|
+
def agent_list
|
199
|
+
r = Helper.with(options).agent_list
|
200
|
+
puts "errcode: #{r['errcode']} errmsg: #{r['errmsg']}"
|
201
|
+
puts 'ag# name square_logo_url round_logo_url'
|
202
|
+
r['agentlist'].sort_by { |d| d['agentid'] } .each do |i|
|
203
|
+
puts format('%3d %s %s %s', i['agentid'], i['name'], i['square_logo_url'], i['round_logo_url'])
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
desc 'agent [AGENT_ID]', '获取企业号应用详情'
|
208
|
+
def agent(agentid)
|
209
|
+
r = Helper.with(options).agent(agentid)
|
210
|
+
puts "agentid: #{r['agentid']} errcode: #{r['errcode']} errmsg: #{r['errmsg']}"
|
211
|
+
puts "name: #{r['name']}"
|
212
|
+
puts "description: #{r['description']}"
|
213
|
+
puts " square_logo_url: #{r['square_logo_url']}"
|
214
|
+
puts " round_logo_url: #{r['round_logo_url']}"
|
215
|
+
puts "allow_userinfos: #{r['allow_userinfos']}"
|
216
|
+
puts "allow_partys: #{r['allow_partys']}"
|
217
|
+
puts "allow_tags: #{r['allow_tags']}"
|
218
|
+
puts "close: #{r['close']} redirect_domain: #{r['redirect_domain']}"
|
219
|
+
puts "report_location_flag: #{r['report_location_flag']} isreportuser: #{r['isreportuser']} isreportenter: #{r['isreportenter']}"
|
101
220
|
end
|
102
221
|
|
103
222
|
desc 'users', '关注者列表'
|
@@ -120,6 +239,26 @@ HELP
|
|
120
239
|
puts Helper.with(options).user_delete(userid)
|
121
240
|
end
|
122
241
|
|
242
|
+
desc 'batch_job_result [JOB_ID]', '获取异步任务结果'
|
243
|
+
def batch_job_result(job_id)
|
244
|
+
puts Helper.with(options).batch_job_result(job_id)
|
245
|
+
end
|
246
|
+
|
247
|
+
desc 'batch_replaceparty [BATCH_PARTY_CSV_MEDIA_ID]', '全量覆盖部门'
|
248
|
+
def batch_replaceparty(batch_party_csv_media_id)
|
249
|
+
puts Helper.with(options).batch_replaceparty(batch_party_csv_media_id)
|
250
|
+
end
|
251
|
+
|
252
|
+
desc 'batch_syncuser [SYNC_USER_CSV_MEDIA_ID]', '增量更新成员'
|
253
|
+
def batch_syncuser(sync_user_csv_media_id)
|
254
|
+
puts Helper.with(options).batch_syncuser(sync_user_csv_media_id)
|
255
|
+
end
|
256
|
+
|
257
|
+
desc 'batch_replaceuser [BATCH_USER_CSV_MEDIA_ID]', '全量覆盖成员'
|
258
|
+
def batch_replaceuser(batch_user_csv_media_id)
|
259
|
+
puts Helper.with(options).batch_replaceuser(batch_user_csv_media_id)
|
260
|
+
end
|
261
|
+
|
123
262
|
desc 'user_group [OPEN_ID]', '查询用户所在分组'
|
124
263
|
def user_group(openid)
|
125
264
|
puts Helper.with(options).user_group(openid)
|
@@ -130,6 +269,21 @@ HELP
|
|
130
269
|
puts Helper.with(options).user_change_group(openid, to_groupid)
|
131
270
|
end
|
132
271
|
|
272
|
+
desc 'user_update_remark [OPEN_ID, REMARK]', '设置备注名'
|
273
|
+
def user_update_remark(openid, remark)
|
274
|
+
puts Helper.with(options).user_update_remark(openid, remark)
|
275
|
+
end
|
276
|
+
|
277
|
+
desc 'qrcode_create_scene [SCENE_ID, EXPIRE_SECONDS]', '请求临时二维码'
|
278
|
+
def qrcode_create_scene(scene_id, expire_seconds = 604800)
|
279
|
+
puts Helper.with(options).qrcode_create_scene(scene_id, expire_seconds)
|
280
|
+
end
|
281
|
+
|
282
|
+
desc 'qrcode_create_limit_scene [SCENE_ID_OR_STR]', '请求永久二维码'
|
283
|
+
def qrcode_create_limit_scene(scene_id_or_str)
|
284
|
+
puts Helper.with(options).qrcode_create_limit_scene(scene_id_or_str)
|
285
|
+
end
|
286
|
+
|
133
287
|
desc 'menu', '当前菜单'
|
134
288
|
def menu
|
135
289
|
puts Helper.with(options).menu
|
@@ -142,7 +296,7 @@ HELP
|
|
142
296
|
|
143
297
|
desc 'menu_create [MENU_YAML_PATH]', '创建菜单'
|
144
298
|
def menu_create(menu_yaml_path)
|
145
|
-
menu = YAML.load(File.
|
299
|
+
menu = YAML.load(File.read(menu_yaml_path))
|
146
300
|
puts 'Menu created' if Helper.with(options).menu_create(menu)
|
147
301
|
end
|
148
302
|
|
@@ -177,11 +331,24 @@ HELP
|
|
177
331
|
puts Helper.with(options).material_delete(media_id)
|
178
332
|
end
|
179
333
|
|
180
|
-
desc 'material_count', '
|
334
|
+
desc 'material_count', '获取永久素材总数'
|
181
335
|
def material_count
|
182
336
|
puts Helper.with(options).material_count
|
183
337
|
end
|
184
338
|
|
339
|
+
desc 'material_list [TYPE, OFFSET, COUNT]', '获取永久素材列表'
|
340
|
+
def material_list(type, offset, count)
|
341
|
+
r = Helper.with(options).material_list(type, offset, count)
|
342
|
+
if %w(image voice video file).include?(type)
|
343
|
+
puts "errcode: #{r['errcode']} errmsg: #{r['errmsg']} total_count: #{r['total_count']} item_count: #{r['item_count']}"
|
344
|
+
r['itemlist'].each do |i|
|
345
|
+
puts "#{i['media_id']} #{i['filename']} #{Time.at(i['update_time'].to_i)}"
|
346
|
+
end
|
347
|
+
else
|
348
|
+
puts r
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
185
352
|
desc 'message_send [OPENID, TEXT_MESSAGE]', '发送文字消息(仅企业号)'
|
186
353
|
def message_send(openid, text_message)
|
187
354
|
puts Helper.with(options).message_send openid, text_message
|
@@ -237,13 +404,13 @@ HELP
|
|
237
404
|
|
238
405
|
desc 'custom_news [OPENID, NEWS_YAML_PATH]', '发送图文客服消息'
|
239
406
|
def custom_news(openid, news_yaml_path)
|
240
|
-
articles = YAML.load(File.
|
407
|
+
articles = YAML.load(File.read(news_yaml_path))
|
241
408
|
puts Helper.with(options).custom_message_send Wechat::Message.to(openid).news(articles['articles'])
|
242
409
|
end
|
243
410
|
|
244
411
|
desc 'template_message [OPENID, TEMPLATE_YAML_PATH]', '模板消息接口'
|
245
412
|
def template_message(openid, template_yaml_path)
|
246
|
-
template = YAML.load(File.
|
413
|
+
template = YAML.load(File.read(template_yaml_path))
|
247
414
|
puts Helper.with(options).template_message_send Wechat::Message.to(openid).template(template['template'])
|
248
415
|
end
|
249
416
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Wechat
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc 'Install Wechat support files'
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
|
7
|
+
def copy_config
|
8
|
+
template 'config/wechat.yml'
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_wechat_route
|
12
|
+
route 'resource :wechat, only: [:show, :create]'
|
13
|
+
end
|
14
|
+
|
15
|
+
def copy_wechat_controller
|
16
|
+
template 'app/controllers/wechats_controller.rb'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class WechatsController < ApplicationController
|
2
|
+
wechat_responder
|
3
|
+
|
4
|
+
# default text responder when no other match
|
5
|
+
on :text do |request, content|
|
6
|
+
request.reply.text "echo: #{content}" # Just echo
|
7
|
+
end
|
8
|
+
|
9
|
+
# When receive 'help', will trigger this responder
|
10
|
+
on :text, with: 'help' do |request|
|
11
|
+
request.reply.text 'help content'
|
12
|
+
end
|
13
|
+
|
14
|
+
# When receive '<n>news', will match and will got count as <n> as parameter
|
15
|
+
on :text, with: /^(\d+) news$/ do |request, count|
|
16
|
+
# Wechat article can only contain max 10 items, large than 10 will dropped.
|
17
|
+
news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: 'News title', content: "No. #{n} news content" } }
|
18
|
+
request.reply.news(news) do |article, n, index| # article is return object
|
19
|
+
article.item title: "#{index} #{n[:title]}", description: n[:content], pic_url: 'http://www.baidu.com/img/bdlogo.gif', url: 'http://www.baidu.com/'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# When user press menu BINDING_QR_CODE and success to scan bar code
|
24
|
+
on :event, with: 'BINDING_QR_CODE' do |request, scan_result, scan_type|
|
25
|
+
request.reply.text "User #{request[:FromUserName]} ScanResult #{scan_result} ScanType #{scan_type}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Except QR code, wechat can also scan CODE_39 bar code
|
29
|
+
on :event, with: 'BINDING_BARCODE' do |message, scan_result|
|
30
|
+
if scan_result.start_with? 'CODE_39,'
|
31
|
+
message.reply.text "User: #{message[:FromUserName]} scan barcode, result is #{scan_result.split(',')[1]}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# When user sent the imsage
|
36
|
+
on :image do |request|
|
37
|
+
request.reply.image(request[:MediaId]) # Echo the sent image to user
|
38
|
+
end
|
39
|
+
|
40
|
+
# When user sent the voice
|
41
|
+
on :voice do |request|
|
42
|
+
request.reply.voice(request[:MediaId]) # Echo the sent voice to user
|
43
|
+
end
|
44
|
+
|
45
|
+
# When user sent the video
|
46
|
+
on :video do |request|
|
47
|
+
nickname = wechat.user(request[:FromUserName])['nickname'] # Call wechat api to get sender nickname
|
48
|
+
request.reply.video(request[:MediaId], title: 'Echo', description: "Got #{nickname} sent video") # Echo the sent video to user
|
49
|
+
end
|
50
|
+
|
51
|
+
# When user sent location
|
52
|
+
on :location do |request|
|
53
|
+
request.reply.text("#{request[:Location_X]}, #{request[:Location_Y]}") # replay the GPS location
|
54
|
+
end
|
55
|
+
|
56
|
+
on :event, with: 'subscribe' do |request|
|
57
|
+
request.reply.text "#{request[:FromUserName]} subscribe now"
|
58
|
+
end
|
59
|
+
|
60
|
+
on :event, with: 'unsubscribe' do |request|
|
61
|
+
request.reply.text "#{request[:FromUserName]} can not receive this message"
|
62
|
+
end
|
63
|
+
|
64
|
+
# When user enter the app / agent app
|
65
|
+
on :event, with: 'enter_agent' do |request|
|
66
|
+
request.reply.text "#{request[:FromUserName]} enter agent app now"
|
67
|
+
end
|
68
|
+
|
69
|
+
# When batch job create/update user (incremental) finished.
|
70
|
+
on :event, with: 'sync_user' do |request, batch_job|
|
71
|
+
request.reply.text "sync_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# When batch job replace user (full sync) finished.
|
75
|
+
on :event, with: 'replace_user' do |request, batch_job|
|
76
|
+
request.reply.text "replace_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
77
|
+
end
|
78
|
+
|
79
|
+
# When batch job invent user finished.
|
80
|
+
on :event, with: 'invite_user' do |request, batch_job|
|
81
|
+
request.reply.text "invite_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# When batch job replace department (full sync) finished.
|
85
|
+
on :event, with: 'replace_party' do |request, batch_job|
|
86
|
+
request.reply.text "replace_party job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Any not match above will fail to below
|
90
|
+
on :fallback, respond: 'fallback message'
|
91
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
default: &default
|
2
|
+
corpid: "corpid"
|
3
|
+
corpsecret: "corpsecret"
|
4
|
+
agentid: 1
|
5
|
+
# Or if using public account, only need above two line
|
6
|
+
# appid: "my_appid"
|
7
|
+
# secret: "my_secret"
|
8
|
+
token: "token"
|
9
|
+
access_token: "C:/Users/[username]/wechat_access_token"
|
10
|
+
encoding_aes_key: "encoding_aes_key"
|
11
|
+
|
12
|
+
production:
|
13
|
+
corpid: <%%= ENV['WECHAT_CORPID'] %>
|
14
|
+
corpsecret: <%%= ENV['WECHAT_CORPSECRET'] %>
|
15
|
+
agentid: <%%= ENV['WECHAT_AGENTID'] %>
|
16
|
+
# Or if using public account, only need above two line
|
17
|
+
# appid: <%= ENV['WECHAT_APPID'] %>
|
18
|
+
# secret: <%= ENV['WECHAT_APP_SECRET'] %>
|
19
|
+
token: <%%= ENV['WECHAT_TOKEN'] %>
|
20
|
+
access_token: <%%= ENV['WECHAT_ACCESS_TOKEN'] %>
|
21
|
+
encoding_aes_key: <%%= ENV['WECHAT_ENCODING_AES_KEY'] %>
|
22
|
+
|
23
|
+
development:
|
24
|
+
<<: *default
|
25
|
+
|
26
|
+
test:
|
27
|
+
<<: *default
|
data/lib/wechat/api.rb
CHANGED
@@ -18,7 +18,7 @@ module Wechat
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def groups
|
21
|
-
get
|
21
|
+
get 'groups/get'
|
22
22
|
end
|
23
23
|
|
24
24
|
def group_create(group_name)
|
@@ -39,7 +39,7 @@ module Wechat
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def user(openid)
|
42
|
-
get
|
42
|
+
get 'user/info', params: { openid: openid }
|
43
43
|
end
|
44
44
|
|
45
45
|
def user_group(openid)
|
@@ -50,17 +50,38 @@ module Wechat
|
|
50
50
|
post 'groups/members/update', JSON.generate(openid: openid, to_groupid: to_groupid)
|
51
51
|
end
|
52
52
|
|
53
|
+
def user_update_remark(openid, remark)
|
54
|
+
post 'user/info/updateremark', JSON.generate(openid: openid, remark: remark)
|
55
|
+
end
|
56
|
+
|
57
|
+
def qrcode_create_scene(scene_id, expire_seconds = 604800)
|
58
|
+
post 'qrcode/create', JSON.generate(expire_seconds: expire_seconds,
|
59
|
+
action_name: 'QR_SCENE',
|
60
|
+
action_info: { scene: { scene_id: scene_id } })
|
61
|
+
end
|
62
|
+
|
63
|
+
def qrcode_create_limit_scene(scene_id_or_str)
|
64
|
+
case scene_id_or_str
|
65
|
+
when Fixnum
|
66
|
+
post 'qrcode/create', JSON.generate(action_name: 'QR_LIMIT_SCENE',
|
67
|
+
action_info: { scene: { scene_id: scene_id_or_str } })
|
68
|
+
else
|
69
|
+
post 'qrcode/create', JSON.generate(action_name: 'QR_LIMIT_STR_SCENE',
|
70
|
+
action_info: { scene: { scene_str: scene_id_or_str } })
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
53
74
|
def menu
|
54
|
-
get
|
75
|
+
get 'menu/get'
|
55
76
|
end
|
56
77
|
|
57
78
|
def menu_delete
|
58
|
-
get
|
79
|
+
get 'menu/delete'
|
59
80
|
end
|
60
81
|
|
61
82
|
def menu_create(menu)
|
62
83
|
# 微信不接受7bit escaped json(eg \uxxxx), 中文必须UTF-8编码, 这可能是个安全漏洞
|
63
|
-
post
|
84
|
+
post 'menu/create', JSON.generate(menu)
|
64
85
|
end
|
65
86
|
|
66
87
|
def media(media_id)
|
@@ -79,6 +100,10 @@ module Wechat
|
|
79
100
|
get 'material/get_materialcount'
|
80
101
|
end
|
81
102
|
|
103
|
+
def material_list(type, offset, count)
|
104
|
+
post 'material/batchget_material', JSON.generate(type: type, offset: offset, count: count)
|
105
|
+
end
|
106
|
+
|
82
107
|
def material_add(type, file)
|
83
108
|
post 'material/add_material', { upload: { media: file } }, params: { type: type }, base: FILE_BASE
|
84
109
|
end
|
data/lib/wechat/api_base.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
1
3
|
module Wechat
|
2
4
|
class ApiBase
|
3
5
|
attr_reader :access_token, :client
|
4
6
|
|
7
|
+
MP_BASE = 'https://mp.weixin.qq.com/cgi-bin/'
|
8
|
+
|
5
9
|
def callbackip
|
6
|
-
get
|
10
|
+
get 'getcallbackip'
|
11
|
+
end
|
12
|
+
|
13
|
+
def qrcode(ticket)
|
14
|
+
client.get 'showqrcode', ticket: CGI.escape(ticket), base: MP_BASE, as: :file
|
7
15
|
end
|
8
16
|
|
9
17
|
protected
|
data/lib/wechat/corp_api.rb
CHANGED
@@ -23,8 +23,16 @@ module Wechat
|
|
23
23
|
@agentid = agentid
|
24
24
|
end
|
25
25
|
|
26
|
+
def agent_list
|
27
|
+
get 'agent/list'
|
28
|
+
end
|
29
|
+
|
30
|
+
def agent(agentid)
|
31
|
+
get 'agent/get', params: { agentid: agentid }
|
32
|
+
end
|
33
|
+
|
26
34
|
def user(userid)
|
27
|
-
get
|
35
|
+
get 'user/get', params: { userid: userid }
|
28
36
|
end
|
29
37
|
|
30
38
|
def invite_user(userid)
|
@@ -32,27 +40,83 @@ module Wechat
|
|
32
40
|
end
|
33
41
|
|
34
42
|
def user_auth_success(userid)
|
35
|
-
get
|
43
|
+
get 'user/authsucc', params: { userid: userid }
|
36
44
|
end
|
37
45
|
|
38
46
|
def user_delete(userid)
|
39
|
-
get
|
47
|
+
get 'user/delete', params: { userid: userid }
|
48
|
+
end
|
49
|
+
|
50
|
+
def batch_job_result(jobid)
|
51
|
+
get 'batch/getresult', params: { jobid: jobid }
|
52
|
+
end
|
53
|
+
|
54
|
+
def batch_replaceparty(media_id)
|
55
|
+
post 'batch/replaceparty', JSON.generate(media_id: media_id)
|
56
|
+
end
|
57
|
+
|
58
|
+
def batch_syncuser(media_id)
|
59
|
+
post 'batch/syncuser', JSON.generate(media_id: media_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def batch_replaceuser(media_id)
|
63
|
+
post 'batch/replaceuser', JSON.generate(media_id: media_id)
|
40
64
|
end
|
41
65
|
|
42
66
|
def department_create(name, parentid)
|
43
|
-
post
|
67
|
+
post 'department/create', JSON.generate(name: name, parentid: parentid)
|
68
|
+
end
|
69
|
+
|
70
|
+
def department_delete(departmentid)
|
71
|
+
get 'department/delete', params: { id: departmentid }
|
44
72
|
end
|
45
73
|
|
46
74
|
def department(departmentid = 1)
|
47
|
-
get
|
75
|
+
get 'department/list', params: { id: departmentid }
|
76
|
+
end
|
77
|
+
|
78
|
+
def user_simplelist(departmentid, fetch_child = 0, status = 0)
|
79
|
+
get 'user/simplelist', params: { departmentid: departmentid, fetch_child: fetch_child, status: status }
|
80
|
+
end
|
81
|
+
|
82
|
+
def user_list(departmentid, fetch_child = 0, status = 0)
|
83
|
+
get 'user/list', params: { departmentid: departmentid, fetch_child: fetch_child, status: status }
|
84
|
+
end
|
85
|
+
|
86
|
+
def tag_create(tagname, tagid = nil)
|
87
|
+
post 'tag/create', JSON.generate(tagname: tagname, tagid: tagid)
|
88
|
+
end
|
89
|
+
|
90
|
+
def tag_update(tagid, tagname)
|
91
|
+
post 'tag/update', JSON.generate(tagid: tagid, tagname: tagname)
|
92
|
+
end
|
93
|
+
|
94
|
+
def tag_delete(tagid)
|
95
|
+
get 'tag/delete', params: { tagid: tagid }
|
96
|
+
end
|
97
|
+
|
98
|
+
def tags
|
99
|
+
get 'tag/list'
|
100
|
+
end
|
101
|
+
|
102
|
+
def tag(tagid)
|
103
|
+
get 'tag/get', params: { tagid: tagid }
|
104
|
+
end
|
105
|
+
|
106
|
+
def tag_add_user(tagid, userids = nil, departmentids = nil)
|
107
|
+
post 'tag/addtagusers', JSON.generate(tagid: tagid, userlist: userids, partylist: departmentids)
|
108
|
+
end
|
109
|
+
|
110
|
+
def tag_del_user(tagid, userids = nil, departmentids = nil)
|
111
|
+
post 'tag/deltagusers', JSON.generate(tagid: tagid, userlist: userids, partylist: departmentids)
|
48
112
|
end
|
49
113
|
|
50
114
|
def menu
|
51
|
-
get
|
115
|
+
get 'menu/get', params: { agentid: agentid }
|
52
116
|
end
|
53
117
|
|
54
118
|
def menu_delete
|
55
|
-
get
|
119
|
+
get 'menu/delete', params: { agentid: agentid }
|
56
120
|
end
|
57
121
|
|
58
122
|
def menu_create(menu)
|
@@ -68,6 +132,10 @@ module Wechat
|
|
68
132
|
get 'material/get_count', params: { agentid: agentid }
|
69
133
|
end
|
70
134
|
|
135
|
+
def material_list(type, offset, count)
|
136
|
+
post 'material/batchget', JSON.generate(type: type, agentid: agentid, offset: offset, count: count)
|
137
|
+
end
|
138
|
+
|
71
139
|
def media_create(type, file)
|
72
140
|
post 'media/upload', { upload: { media: file } }, params: { type: type }
|
73
141
|
end
|
data/lib/wechat/responder.rb
CHANGED
@@ -25,30 +25,33 @@ module Wechat
|
|
25
25
|
config.merge!(with: with) if with.present?
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
user_defined_responders(message_type) << config
|
29
29
|
config
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def user_defined_responders(type)
|
33
33
|
@responders ||= {}
|
34
34
|
@responders[type] ||= []
|
35
35
|
end
|
36
36
|
|
37
|
-
def responder_for(message
|
37
|
+
def responder_for(message)
|
38
38
|
message_type = message[:MsgType].to_sym
|
39
|
-
responders =
|
39
|
+
responders = user_defined_responders(message_type)
|
40
40
|
|
41
41
|
case message_type
|
42
42
|
when :text
|
43
43
|
yield(* match_responders(responders, message[:Content]))
|
44
|
-
|
45
44
|
when :event
|
46
45
|
if 'click' == message[:Event]
|
47
46
|
yield(* match_responders(responders, message[:EventKey]))
|
48
47
|
elsif %w(scancode_push scancode_waitmsg).include? message[:Event]
|
49
|
-
yield(* match_responders(responders,
|
48
|
+
yield(* match_responders(responders, event: 'scancode',
|
49
|
+
event_key: message[:EventKey],
|
50
50
|
scan_type: message[:ScanCodeInfo][:ScanType],
|
51
51
|
scan_result: message[:ScanCodeInfo][:ScanResult]))
|
52
|
+
elsif 'batch_job_result' == message[:Event]
|
53
|
+
yield(* match_responders(responders, event: 'batch_job',
|
54
|
+
batch_job: message[:BatchJob]))
|
52
55
|
else
|
53
56
|
yield(* match_responders(responders, message[:Event]))
|
54
57
|
end
|
@@ -71,7 +74,9 @@ module Wechat
|
|
71
74
|
if condition.is_a? Regexp
|
72
75
|
memo[:scoped] ||= [responder] + $LAST_MATCH_INFO.captures if value =~ condition
|
73
76
|
elsif value.is_a? Hash
|
74
|
-
memo[:scoped] ||= [responder, value[:scan_result], value[:scan_type]] if value[:event_key] == condition
|
77
|
+
memo[:scoped] ||= [responder, value[:scan_result], value[:scan_type]] if value[:event_key] == condition && value[:event] == 'scancode'
|
78
|
+
memo[:scoped] ||= [responder, value[:batch_job]] if value[:event] == 'batch_job' &&
|
79
|
+
%w(sync_user replace_user invite_user replace_party).include?(condition.downcase)
|
75
80
|
else
|
76
81
|
memo[:scoped] ||= [responder, value] if value == condition
|
77
82
|
end
|
@@ -133,7 +138,7 @@ module Wechat
|
|
133
138
|
|
134
139
|
def run_responder(request)
|
135
140
|
self.class.responder_for(request) do |responder, *args|
|
136
|
-
responder ||= self.class.
|
141
|
+
responder ||= self.class.user_defined_responders(:fallback).first
|
137
142
|
|
138
143
|
next if responder.nil?
|
139
144
|
case
|
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.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Skinnyworm
|
@@ -9,10 +9,10 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-09-
|
12
|
+
date: 2015-09-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: activesupport
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
@@ -67,6 +67,20 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '3.3'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rails
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '3.2'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '3.2'
|
70
84
|
description: API and message handling for WeChat in Rails
|
71
85
|
email: eric.guocz@gmail.com
|
72
86
|
executables:
|
@@ -80,6 +94,9 @@ files:
|
|
80
94
|
- Rakefile
|
81
95
|
- bin/wechat
|
82
96
|
- lib/action_controller/wechat_responder.rb
|
97
|
+
- lib/generators/wechat/install_generator.rb
|
98
|
+
- lib/generators/wechat/templates/app/controllers/wechats_controller.rb
|
99
|
+
- lib/generators/wechat/templates/config/wechat.yml
|
83
100
|
- lib/wechat.rb
|
84
101
|
- lib/wechat/access_token.rb
|
85
102
|
- lib/wechat/api.rb
|