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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 51c5c439ece595c22e3382f948a56643c49fe613
4
- data.tar.gz: 79f38b3fb01e9ffe6b6ef25beb214ff7976ce3f6
3
+ metadata.gz: bfc807dea051fded9c082a6bdbf4778433b2bbce
4
+ data.tar.gz: 55e132829fc449ed8fd9ec591ee05710386037bb
5
5
  SHA512:
6
- metadata.gz: 22bc4cf0506b8a59f4f13c3bf209dff2e723693e40abb8472e3abf1578c3f155c133ed7f5861998e8f7a371250fbfdb726124ccb5c7e9950b5a8137a1766d65a
7
- data.tar.gz: 1f8c0f29f74dd3ce86c6829a0f4bc594241ce70b0353946b886425332cf8d97c86bc531915d8d2c9b819438ac39d6bca76665001fd264971954f8e563d52cbf8
6
+ metadata.gz: f4b26ce081c96d50de0e02340a6745f3cdff6334dfbdc7a521f74ee06136521ccbd42e7cf0ae2e52ba71e9dc73384e287de0c76486a95a8f0c12c4cbc3d98437
7
+ data.tar.gz: 2d6867ec622f4ae9748072eeeac18a19536579d8b74a1c56d3e59ebdf886b85a0de5dd694376fd2a0db7ca2b16542109f9eee5a6ad41d978e5dab3b903e3737a
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.7.6 (released at 3/05/2016)
4
+
5
+ * Support wechat public account conditional menu. #95
6
+
3
7
  ## v0.7.5 (released at 2/21/2016)
4
8
 
5
9
  * New wechat_config_js to simplify the Wechat jsapi config.
@@ -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
- 创建菜单需要一个定义菜单内容的yaml文件,比如
330
- menu.yaml
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
- 然后执行命令行,需确保设置,权限管理中有对此应用的管理权限,否则会报[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)错。
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
- menu content for a wechat application can be defined as a yaml files, like `menu.yaml`
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
- 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.
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
@@ -0,0 +1,3 @@
1
+ Run `wechat menu_create config\wechat_menu.yml` to uploading the default menu.
2
+ Run `rails g wechat:menu --conditional` to generate one example of conditional menu.
3
+ Run `wechat menu_addconditional config\wechat_menu_conditional.yml` to uploading the conditional menu.
@@ -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(response_message)
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,6 @@
1
+ # More option see https://github.com/Eric-Guo/wechat#menu-create
2
+ button:
3
+ -
4
+ type: "view"
5
+ name: "Testing"
6
+ url: "http://xxxxx.proxy.qqbrowser.cc"
@@ -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
@@ -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
@@ -2,7 +2,7 @@ module Wechat
2
2
  class ApiBase
3
3
  attr_reader :access_token, :client, :jsapi_ticket
4
4
 
5
- MP_BASE = 'https://mp.weixin.qq.com/cgi-bin/'
5
+ MP_BASE = 'https://mp.weixin.qq.com/cgi-bin/'.freeze
6
6
 
7
7
  def callbackip
8
8
  get 'getcallbackip'
@@ -7,7 +7,7 @@ module Wechat
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  BLOCK_SIZE = 32
10
- CIPHER = 'AES-256-CBC'
10
+ CIPHER = 'AES-256-CBC'.freeze
11
11
 
12
12
  def encrypt(plain, encoding_aes_key)
13
13
  cipher = OpenSSL::Cipher.new(CIPHER)
@@ -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)
@@ -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.5
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-02-21 00:00:00.000000000 Z
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