wechat 0.7.7 → 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1227afa2c59a9657b91eda79d71e05c582dfd13c
4
- data.tar.gz: 1ed732c34360e25275a35fa5ddbc62f9fe945e4c
3
+ metadata.gz: 53ffffaf24d8d96f29551c79c5de7ffa1829a918
4
+ data.tar.gz: d98f374eda600f2c61a1ce1dfcbe408663538b08
5
5
  SHA512:
6
- metadata.gz: 358ebfbe074a0a0f631c2966b4cb8f0d3357d37fa8c6a0e67c87863d1b98030bcd625de8cdbbd36cac923e1378ed395599e8199659c8ccf41065085e7d05e57d
7
- data.tar.gz: 95d512581d896582438b0a3c30d9994defaa485118ecf7c5fe90a0ad473ff4508f070aea1153abbabc2ce36bf3c8ad3a521319b9cf92b4cb98c2ed48999f9bc4
6
+ metadata.gz: f3a9d2da9c57c99b535c5f1f29a36f796100f23997386cfe922415df30aeb5d32e0e0634e99f6e5cf58e3ba2d1bf8b0e6a47bccdc4d3e1eb2db84d48fff9af61
7
+ data.tar.gz: f8913573a84ca830f21b14be23d446b336ef4daa010ec2501185dd3da102cc98244ef3e6ddc74d72b7b9781ce452e7065f8614b86690c62148742a564c771563
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.7.8 (released at 3/31/2016)
4
+
5
+ * New wechat_api, similar to wechat_responder, but without messange handle DSL, support web page only wechat application
6
+ * New media_uploadimg API.
7
+ * New file type of Message.
8
+ * Improved multi account support per different controller.
9
+
3
10
  ## v0.7.7 (released at 3/18/2016)
4
11
 
5
12
  * New wechat_oauth2, only support enterprise account still.
@@ -17,6 +17,8 @@ WeChat gem 可以帮助开发者方便地在Rails环境中集成微信[公众平
17
17
 
18
18
  如果您对如何制作微信网页UI没有灵感,可以参考官方的[weui](https://github.com/weui/weui),针对Rails的Gem是[weui-rails](https://github.com/Eric-Guo/weui-rails)。
19
19
 
20
+ 主页型应用请使用[`wechat_api`](#wechat_api---rails-controller-wechat-api),传统消息型应用请使用[`wechat_responder`](#wechat_responder---rails-responder-controller-dsl)。
21
+
20
22
  如果您想从一个稍微完整一些的示例开始微信开发,可以参考[wechat-starter](https://github.com/goofansu/wechat-starter),这个示例甚至包括了微信支付的内容。
21
23
 
22
24
  ## 安装
@@ -164,7 +166,7 @@ Wechat服务器有报道曾出现[RestClient::SSLCertificateNotVerified](http://
164
166
 
165
167
  #### 为每个Responder配置不同的appid和secret
166
168
 
167
- 在个别情况下,单个Rails应用可能需要处理来自多个账号的消息,此时可以配置多个responder controller。
169
+ 有些情况下,单个Rails应用可能需要处理来自多个微信公众号的消息,您可以通过在`wechat_responder`和`wechat_api`后配置多个相关参数来支持多账号。
168
170
 
169
171
  ```ruby
170
172
  class WechatFirstController < ActionController::Base
@@ -244,6 +246,7 @@ Wechat commands:
244
246
  wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
245
247
  wechat media [MEDIA_ID, PATH] # 媒体下载
246
248
  wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
249
+ wechat media_uploadimg [IMAGE_PATH] # 上传图文消息内的图片
247
250
  wechat menu # 当前菜单
248
251
  wechat menu_addconditional [CONDITIONAL_MENU_YAML_PATH] # 创建个性化菜单
249
252
  wechat menu_create [MENU_YAML_PATH] # 创建菜单
@@ -292,6 +295,7 @@ Wechat commands:
292
295
  wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
293
296
  wechat media [MEDIA_ID, PATH] # 媒体下载
294
297
  wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
298
+ wechat media_uploadimg [IMAGE_PATH] # 上传图文消息内的图片
295
299
  wechat menu # 当前菜单
296
300
  wechat menu_create [MENU_YAML_PATH] # 创建菜单
297
301
  wechat menu_delete # 删除菜单
@@ -447,7 +451,22 @@ template:
447
451
  $ wechat template_message oCfEht9oM*********** template.yml
448
452
  ```
449
453
 
450
- ## Rails Responder Controller DSL
454
+ ## wechat_api - Rails Controller Wechat API
455
+
456
+ 虽然用户可以随时通过`Wechat.api`在任意代码中访问wechat的API功能,但是更推荐的做法是仅在controller中,通过引入`wechat_api`,使用`wechat`调用API功能,不仅因为这样是支持多个微信公众号的必然要求,而且也避免了在模型层内过多引入微信相关代码。
457
+
458
+ ```ruby
459
+ class WechatReportsController < ApplicationController
460
+ wechat_api
461
+ layout 'wechat'
462
+
463
+ def index
464
+ @lots = Lot.with_preloading.wip_lot
465
+ end
466
+ end
467
+ ```
468
+
469
+ ## wechat_responder - Rails Responder Controller DSL
451
470
 
452
471
  为了在Rails app中响应用户的消息,开发者需要创建一个wechat responder controller. 首先在router中定义
453
472
 
data/README.md CHANGED
@@ -24,6 +24,8 @@ Wechat provide OAuth2.0 authentication method `wechat_oauth2`, possible the easi
24
24
 
25
25
  There is official [weui](https://github.com/weui/weui), which corresponding Rails gems called [weui-rails](https://github.com/Eric-Guo/weui-rails) available, if you prefer following the same UI design as wechat.
26
26
 
27
+ For web page only wechat application, using [`wechat_api`](#wechat_api---rails-controller-wechat-api), which only contain web feature compare with traditional message type [`wechat_responder`](#wechat_responder---rails-responder-controller-dsl).
28
+
27
29
  There is a more complete [wechat-starter](https://github.com/goofansu/wechat-starter) demo available, even include the payment SDK feature.
28
30
 
29
31
  ## Installation
@@ -177,7 +179,7 @@ SSL Certification can also be corrupted by some reason in China, [it's reported]
177
179
 
178
180
  #### Configure individual responder with different appid
179
181
 
180
- Rare case, you may want to hosting more than one wechat enterprise/public account in one Rails application, so you can given those configuration info when calling `wechat_responder`
182
+ Sometime, you may want to hosting more than one enterprise/public wechat account in one Rails application, so you can given those configuration info when calling `wechat_responder` or `wechat_api`
181
183
 
182
184
  ```ruby
183
185
  class WechatFirstController < ActionController::Base
@@ -260,6 +262,7 @@ Wechat commands:
260
262
  wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
261
263
  wechat media [MEDIA_ID, PATH] # 媒体下载
262
264
  wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
265
+ wechat media_uploadimg [IMAGE_PATH] # 上传图文消息内的图片
263
266
  wechat menu # 当前菜单
264
267
  wechat menu_addconditional [CONDITIONAL_MENU_YAML_PATH] # 创建个性化菜单
265
268
  wechat menu_create [MENU_YAML_PATH] # 创建菜单
@@ -308,6 +311,7 @@ Wechat commands:
308
311
  wechat material_list [TYPE, OFFSET, COUNT] # 获取永久素材列表
309
312
  wechat media [MEDIA_ID, PATH] # 媒体下载
310
313
  wechat media_create [MEDIA_TYPE, PATH] # 媒体上传
314
+ wechat media_uploadimg [IMAGE_PATH] # 上传图文消息内的图片
311
315
  wechat menu # 当前菜单
312
316
  wechat menu_create [MENU_YAML_PATH] # 创建菜单
313
317
  wechat menu_delete # 删除菜单
@@ -462,7 +466,22 @@ After that, can running command:
462
466
  $ wechat template_message oCfEht9oM*********** template.yml
463
467
  ```
464
468
 
465
- ## Rails Responder Controller DSL
469
+ ## wechat_api - Rails Controller Wechat API
470
+
471
+ Although user can always access all wechat feature via Wechat.api, but it's much more recommand to using `wechat` directly in controller. It's not only mandatory require if you plan to support multi-account, also help to seperate the wechat specific logic from the model layer.
472
+
473
+ ```ruby
474
+ class WechatReportsController < ApplicationController
475
+ wechat_api
476
+ layout 'wechat'
477
+
478
+ def index
479
+ @lots = Lot.with_preloading.wip_lot
480
+ end
481
+ end
482
+ ```
483
+
484
+ ## wechat_responder - Rails Responder Controller DSL
466
485
 
467
486
  In order to responding the message user sent, Rails developer need create a wechat responder controller and defined the routing in `routes.rb`
468
487
 
data/bin/wechat CHANGED
@@ -343,6 +343,11 @@ class App < Thor
343
343
  puts wechat_api.media_create(type, path)
344
344
  end
345
345
 
346
+ desc 'media_uploadimg [IMAGE_PATH]', '上传图文消息内的图片'
347
+ def media_uploadimg(image_path)
348
+ puts wechat_api.media_uploadimg(image_path)
349
+ end
350
+
346
351
  desc 'material [MEDIA_ID, PATH]', '永久媒体下载'
347
352
  def material(media_id, path)
348
353
  tmp_file = wechat_api.material(media_id)
@@ -1,22 +1,36 @@
1
1
  module ActionController
2
2
  module WechatResponder
3
+ def wechat_api(opts = {})
4
+ include Wechat::ControllerApi
5
+ self.wechat = load_controller_wechat(opts)
6
+ end
7
+
3
8
  def wechat_responder(opts = {})
4
9
  include Wechat::Responder
10
+ self.wechat = load_controller_wechat(opts)
11
+ end
5
12
 
13
+ private_class_method
14
+
15
+ def load_controller_wechat(opts = {})
16
+ self.token = opts[:token] || Wechat.config.token
17
+ self.appid = opts[:appid] || Wechat.config.appid
6
18
  self.corpid = opts[:corpid] || Wechat.config.corpid
7
19
  self.agentid = opts[:agentid] || Wechat.config.agentid
8
20
  self.encrypt_mode = opts[:encrypt_mode] || Wechat.config.encrypt_mode || corpid.present?
9
21
  self.timeout = opts[:timeout] || 20
10
22
  self.skip_verify_ssl = opts[:skip_verify_ssl]
11
- self.token = opts[:token] || Wechat.config.token
12
23
  self.encoding_aes_key = opts[:encoding_aes_key] || Wechat.config.encoding_aes_key
13
24
  self.trusted_domain_fullname = opts[:trusted_domain_fullname] || Wechat.config.trusted_domain_fullname
14
25
 
15
26
  return self.wechat = Wechat.api if opts.empty?
16
- return self.wechat = Wechat::CorpApi.new(corpid, opts[:corpsecret], opts[:access_token], \
17
- agentid, timeout, skip_verify_ssl, opts[:jsapi_ticket]) if corpid.present?
18
- self.wechat = Wechat::Api.new(opts[:appid], opts[:secret], opts[:access_token], \
19
- timeout, skip_verify_ssl, opts[:jsapi_ticket])
27
+ if corpid.present?
28
+ Wechat::CorpApi.new(corpid, opts[:corpsecret], opts[:access_token], \
29
+ agentid, timeout, skip_verify_ssl, opts[:jsapi_ticket])
30
+ else
31
+ Wechat::Api.new(appid, opts[:secret], opts[:access_token], \
32
+ timeout, skip_verify_ssl, opts[:jsapi_ticket])
33
+ end
20
34
  end
21
35
  end
22
36
 
@@ -8,6 +8,7 @@ module Wechat
8
8
  autoload :Message, 'wechat/message'
9
9
  autoload :Responder, 'wechat/responder'
10
10
  autoload :Cipher, 'wechat/cipher'
11
+ autoload :ControllerApi, 'wechat/controller_api'
11
12
 
12
13
  class AccessTokenExpiredError < StandardError; end
13
14
  class ResponseError < StandardError
@@ -20,6 +20,10 @@ module Wechat
20
20
  post_file 'media/upload', file, params: { type: type }
21
21
  end
22
22
 
23
+ def media_uploadimg(file)
24
+ post_file 'media/uploadimg', file
25
+ end
26
+
23
27
  protected
24
28
 
25
29
  def get(path, headers = {})
@@ -27,7 +27,7 @@ HELP
27
27
  @config
28
28
  end
29
29
 
30
- private
30
+ private_class_method
31
31
 
32
32
  def self.loading_config!
33
33
  config ||= config_from_file || config_from_environment
@@ -41,10 +41,10 @@ module Wechat
41
41
  def request(path, header = {}, &_block)
42
42
  url = "#{header.delete(:base) || base}#{path}"
43
43
  as = header.delete(:as)
44
- header.merge!('Accept' => 'application/json')
44
+ header['Accept'] = 'application/json'
45
45
  response = yield(url, header)
46
46
 
47
- fail "Request not OK, response status #{response.status}" if response.status != 200
47
+ raise "Request not OK, response status #{response.status}" if response.status != 200
48
48
  parse_response(response, as || :json) do |parse_as, data|
49
49
  break data unless parse_as == :json && data['errcode'].present?
50
50
 
@@ -56,9 +56,9 @@ module Wechat
56
56
  # 40001, invalid credential, access_token is invalid or not latest hint
57
57
  # 48001, api unauthorized hint, for qrcode creation # 71
58
58
  when 42001, 40014, 40001, 48001
59
- fail AccessTokenExpiredError
59
+ raise AccessTokenExpiredError
60
60
  else
61
- fail ResponseError.new(data['errcode'], data['errmsg'])
61
+ raise ResponseError.new(data['errcode'], data['errmsg'])
62
62
  end
63
63
  end
64
64
  end
@@ -0,0 +1,40 @@
1
+ module Wechat
2
+ module ControllerApi
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ attr_accessor :wechat, :token, :appid, :corpid, :agentid, :encrypt_mode, :timeout, :skip_verify_ssl, :encoding_aes_key, :trusted_domain_fullname
7
+ end
8
+
9
+ def wechat
10
+ self.class.wechat # Make sure user can continue access wechat at instance level similar to class level
11
+ end
12
+
13
+ def wechat_oauth2(scope = 'snsapi_base', page_url = nil)
14
+ appid = self.class.corpid || self.class.appid
15
+ page_url ||= if self.class.trusted_domain_fullname
16
+ "#{self.class.trusted_domain_fullname}#{request.original_fullpath}"
17
+ else
18
+ request.original_url
19
+ end
20
+ redirect_uri = CGI.escape(page_url)
21
+ oauth2_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=#{appid}&redirect_uri=#{redirect_uri}&response_type=code&scope=#{scope}#wechat_redirect"
22
+
23
+ return oauth2_url unless block_given?
24
+ raise 'Currently wechat_oauth2 only support enterprise account.' unless self.class.corpid
25
+ if cookies.signed_or_encrypted[:we_deviceid].blank? && params[:code].blank?
26
+ redirect_to oauth2_url
27
+ elsif cookies.signed_or_encrypted[:we_deviceid].blank? && params[:code].present?
28
+ userinfo = wechat.getuserinfo(params[:code])
29
+ cookies.signed_or_encrypted[:we_userid] = { value: userinfo['UserId'], expires: 1.hour.from_now }
30
+ cookies.signed_or_encrypted[:we_deviceid] = { value: userinfo['DeviceId'], expires: 1.hour.from_now }
31
+ cookies.signed_or_encrypted[:we_openid] = { value: userinfo['OpenId'], expires: 1.hour.from_now }
32
+ yield userinfo['UserId'], userinfo
33
+ else
34
+ yield cookies.signed_or_encrypted[:we_userid], { 'UserId' => cookies.signed_or_encrypted[:we_userid],
35
+ 'DeviceId' => cookies.signed_or_encrypted[:we_deviceid],
36
+ 'OpenId' => cookies.signed_or_encrypted[:we_openid] }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,16 +1,16 @@
1
1
  module Wechat
2
2
  module Helpers
3
3
  def wechat_config_js(config_options = {})
4
- page_url = if Wechat.config.trusted_domain_fullname
5
- "#{Wechat.config.trusted_domain_fullname}#{controller.request.original_fullpath}"
4
+ page_url = if controller.class.trusted_domain_fullname
5
+ "#{controller.class.trusted_domain_fullname}#{controller.request.original_fullpath}"
6
6
  else
7
7
  controller.request.original_url
8
8
  end
9
- js_hash = Wechat.api.jsapi_ticket.signature(page_url)
9
+ js_hash = controller.wechat.jsapi_ticket.signature(page_url)
10
10
  config_js = <<-WECHAT_CONFIG_JS
11
11
  wx.config({
12
12
  debug: #{config_options[:debug]},
13
- appId: "#{Wechat.config.corpid || Wechat.config.appid}",
13
+ appId: "#{controller.class.corpid || controller.class.appid}",
14
14
  timestamp: "#{js_hash[:timestamp]}",
15
15
  nonceStr: "#{js_hash[:noncestr]}",
16
16
  signature: "#{js_hash[:signature]}",
@@ -65,7 +65,7 @@ module Wechat
65
65
  results[value[0].to_s.underscore.to_sym] = value[1]
66
66
  end
67
67
  else
68
- fail "Don't know how to parse message as #{type}"
68
+ raise "Don't know how to parse message as #{type}"
69
69
  end
70
70
  end
71
71
 
@@ -106,6 +106,10 @@ module Wechat
106
106
  update(MsgType: 'video', Video: video_fields)
107
107
  end
108
108
 
109
+ def file(media_id)
110
+ update(MsgType: 'file', File: { MediaId: media_id })
111
+ end
112
+
109
113
  def music(thumb_media_id, music_url, opts = {})
110
114
  music_fields = camelize_hash_keys(opts.slice(:title, :description, :HQ_music_url).merge(music_url: music_url, thumb_media_id: thumb_media_id))
111
115
  update(MsgType: 'music', Music: music_fields)
@@ -145,7 +149,7 @@ module Wechat
145
149
  'TemplateId' => 'template_id'
146
150
  }.freeze
147
151
 
148
- TO_JSON_ALLOWED = %w(touser msgtype content image voice video music news articles template agentid).freeze
152
+ TO_JSON_ALLOWED = %w(touser msgtype content image voice video file music news articles template agentid).freeze
149
153
 
150
154
  def to_json
151
155
  json_hash = deep_recursive(message_hash) do |key, value|
@@ -4,6 +4,7 @@ require 'wechat/signature'
4
4
  module Wechat
5
5
  module Responder
6
6
  extend ActiveSupport::Concern
7
+ include Wechat::ControllerApi
7
8
  include Cipher
8
9
 
9
10
  included do
@@ -26,25 +27,23 @@ module Wechat
26
27
  end
27
28
 
28
29
  module ClassMethods
29
- attr_accessor :wechat, :token, :corpid, :agentid, :encrypt_mode, :timeout, :skip_verify_ssl, :encoding_aes_key, :trusted_domain_fullname
30
-
31
30
  def on(message_type, with: nil, respond: nil, &block)
32
- fail 'Unknow message type' unless [:text, :image, :voice, :video, :shortvideo, :link, :event, :click, :view, :scan, :batch_job, :location, :fallback].include?(message_type)
31
+ raise 'Unknow message type' unless [:text, :image, :voice, :video, :shortvideo, :link, :event, :click, :view, :scan, :batch_job, :location, :fallback].include?(message_type)
33
32
  config = respond.nil? ? {} : { respond: respond }
34
- config.merge!(proc: block) if block_given?
33
+ config[:proc] = block if block_given?
35
34
 
36
35
  if with.present?
37
- fail 'Only text, event, click, view, scan and batch_job can having :with parameters' unless [:text, :event, :click, :view, :scan, :batch_job].include?(message_type)
38
- config.merge!(with: with)
36
+ raise 'Only text, event, click, view, scan and batch_job can having :with parameters' unless [:text, :event, :click, :view, :scan, :batch_job].include?(message_type)
37
+ config[:with] = with
39
38
  if message_type == :scan
40
39
  if with.is_a?(String)
41
40
  self.known_scan_key_lists = with
42
41
  else
43
- fail 'on :scan only support string in parameter with, detail see https://github.com/Eric-Guo/wechat/issues/84'
42
+ raise 'on :scan only support string in parameter with, detail see https://github.com/Eric-Guo/wechat/issues/84'
44
43
  end
45
44
  end
46
45
  else
47
- fail 'Message type click, view, scan and batch_job must specify :with parameters' if [:click, :view, :scan, :batch_job].include?(message_type)
46
+ raise 'Message type click, view, scan and batch_job must specify :with parameters' if [:click, :view, :scan, :batch_job].include?(message_type)
48
47
  end
49
48
 
50
49
  case message_type
@@ -162,37 +161,6 @@ module Wechat
162
161
  end
163
162
  end
164
163
 
165
- def wechat
166
- self.class.wechat # Make sure user can continue access wechat at instance level similar to class level
167
- end
168
-
169
- def wechat_oauth2(scope = 'snsapi_base', page_url = nil)
170
- appid = self.class.corpid || self.class.appid
171
- page_url ||= if self.class.trusted_domain_fullname
172
- "#{self.class.trusted_domain_fullname}#{request.original_fullpath}"
173
- else
174
- request.original_url
175
- end
176
- redirect_uri = CGI.escape(page_url)
177
- oauth2_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=#{appid}&redirect_uri=#{redirect_uri}&response_type=code&scope=#{scope}#wechat_redirect"
178
-
179
- return oauth2_url unless block_given?
180
- raise 'Currently wechat_oauth2 only support enterprise account.' unless self.class.corpid
181
- if cookies.signed_or_encrypted[:we_deviceid].blank? && params[:code].blank?
182
- redirect_to oauth2_url
183
- elsif cookies.signed_or_encrypted[:we_deviceid].blank? && params[:code].present?
184
- userinfo = Wechat.api.getuserinfo(params[:code])
185
- cookies.signed_or_encrypted[:we_userid] = { value: userinfo['UserId'], expires: 1.hour.from_now }
186
- cookies.signed_or_encrypted[:we_deviceid] = { value: userinfo['DeviceId'], expires: 1.hour.from_now }
187
- cookies.signed_or_encrypted[:we_openid] = { value: userinfo['OpenId'], expires: 1.hour.from_now }
188
- yield userinfo['UserId'], userinfo
189
- else
190
- yield cookies.signed_or_encrypted[:we_userid], { 'UserId' => cookies.signed_or_encrypted[:we_userid],
191
- 'DeviceId' => cookies.signed_or_encrypted[:we_deviceid],
192
- 'OpenId' => cookies.signed_or_encrypted[:we_openid] }
193
- end
194
- end
195
-
196
164
  def show
197
165
  if self.class.corpid.present?
198
166
  echostr, _corp_id = unpack(decrypt(Base64.decode64(params[:echostr]), self.class.encoding_aes_key))
@@ -242,9 +210,9 @@ module Wechat
242
210
  msg_encrypt = nil unless self.class.corpid.present?
243
211
 
244
212
  render plain: 'Forbidden', status: 403 if signature != Signature.hexdigest(self.class.token,
245
- params[:timestamp],
246
- params[:nonce],
247
- msg_encrypt)
213
+ params[:timestamp],
214
+ params[:nonce],
215
+ msg_encrypt)
248
216
  end
249
217
 
250
218
  def post_xml
@@ -285,11 +253,7 @@ module Wechat
285
253
  end
286
254
 
287
255
  def process_response(response)
288
- if response[:MsgType] == 'success'
289
- msg = 'success'
290
- else
291
- msg = response.to_xml
292
- end
256
+ msg = response[:MsgType] == 'success' ? 'success' : response.to_xml
293
257
 
294
258
  if self.class.encrypt_mode
295
259
  encrypt = Base64.strict_encode64(encrypt(pack(msg, @app_id), self.class.encoding_aes_key))
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.7
4
+ version: 0.7.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skinnyworm
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-03-18 00:00:00.000000000 Z
12
+ date: 2016-03-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -153,6 +153,7 @@ files:
153
153
  - lib/wechat/api_loader.rb
154
154
  - lib/wechat/cipher.rb
155
155
  - lib/wechat/client.rb
156
+ - lib/wechat/controller_api.rb
156
157
  - lib/wechat/corp_api.rb
157
158
  - lib/wechat/helpers.rb
158
159
  - lib/wechat/message.rb