wechat 0.7.5 → 0.7.6

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: 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