wechat 0.11.9 → 0.12.3

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
  SHA256:
3
- metadata.gz: 370e379885f4c8f7f926fa6a0d7a1d237e0152b9e87d7a87d3732446228b236a
4
- data.tar.gz: 62477c436dd72bb156e22ef936581c881043c9008a077df2cc1f570f089ab43d
3
+ metadata.gz: 4f3b96f4a7e2cd18a4a2407f550cf0437fefa8766e26e1356692918932f6441a
4
+ data.tar.gz: 024176770cbb290d9fa7039dbb395a6d60d0a64dd6ad20777928771be5feb93d
5
5
  SHA512:
6
- metadata.gz: f5e603ac0672f10b6b98ef12b05ada4f1f58cec182d5046daec501666ee8204e6ebbe7e1da874b29876252803a2449835b829cb5a3b159e292fb0a4475370e65
7
- data.tar.gz: e2c40b34f6d0ed589da874ee65745eab5f6588400e0dbd812603da7017017498d4666f784ecf7e06e867722b65bc97f8926e5e5e04d311d25cd0b558a3d52f12
6
+ metadata.gz: 51d9e9ede2d8479c81e9b389e3bcfb3ffcf96a4daee330998d30fcde88cb35f7b36b2cf92754e537720781475105ac59e974047b81bc5c12b462b8a0cf156fa1
7
+ data.tar.gz: '09fa4efec1ba2843ac564f1ef97b71728d91439849175767416abf67263916c1214b434ea542d85ccb9b1f45e3d3a9538f4555eebfe6acfd6ee85e77fb18c3a1'
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.12.3 (released at 3/15/2021)
4
+
5
+ * Fix MpApi initialize bug, by @hardywu #296
6
+
7
+ ## v0.12.2 (released at 3/3/2021)
8
+
9
+ * New convert_to_userid API
10
+
11
+ ## v0.12.1 (released at 28/12/2020)
12
+
13
+ * Support Ruby 3.0.
14
+ * Qcloud_token support.
15
+ * CRUD of tencent cloud DB for miniapp
16
+ * TCB storage API support.
17
+ * Set default branch to *main*.
18
+
19
+ ## v0.11.11 (released at 09/13/2020)
20
+
21
+ * FIX: fix_load_controller_wechat not support MP type, by @Msms-NJ #281
22
+
23
+ ## v0.11.10 (released at 09/02/2020)
24
+
25
+ * ADD: Wechat::MpApi.wxa_msg_sec_check.
26
+
3
27
  ## v0.11.9 (released at 04/29/2020)
4
28
 
5
29
  * CHG: upgrade ssl_version to 1.2 by @paicha #276
data/README-CN.md CHANGED
@@ -1,9 +1,9 @@
1
- WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://travis-ci.org/Eric-Guo/wechat.svg)](https://travis-ci.org/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
1
+ WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://travis-ci.com/Eric-Guo/wechat.svg)](https://travis-ci.com/github/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
2
2
  ======
3
3
 
4
4
  [![Join the chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Eric-Guo/wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
5
 
6
- WeChat gem帮助开发者方便地在Rails环境中集成[微信公众平台](https://mp.weixin.qq.com/)[企业微信](https://qy.weixin.qq.com),包括功能:
6
+ WeChat gem帮助开发者方便地在Rails环境中集成[微信公众平台](https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html)[企业微信](https://work.weixin.qq.com/api/doc)和[小程序](https://developers.weixin.qq.com/miniprogram/dev/framework/),包括功能:
7
7
 
8
8
  - 微信公众平台/企业微信[发送消息](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF)API(命令行和Web环境都可以使用)
9
9
  - [接收消息](http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%E4%B8%8E%E4%BA%8B%E4%BB%B6)(必须运行Web服务器)
@@ -399,6 +399,7 @@ Wechat Public Account commands:
399
399
  wechat user_group [OPEN_ID] # 查询用户所在分组
400
400
  wechat user_update_remark [OPEN_ID, REMARK] # 设置备注名
401
401
  wechat users # 关注者列表
402
+ wechat wxa_msg_sec_check [CONTENT] # 检查一段文本是否含有违法违规内容。
402
403
  wechat wxacode_download [WXA_CODE_PIC_PATH, PATH, WIDTH] # 下载小程序码
403
404
  ```
404
405
 
@@ -415,6 +416,7 @@ Wechat Enterprise Account commands:
415
416
  wechat callbackip # 获取微信服务器IP地址
416
417
  wechat clear_quota # 接口调用次数清零
417
418
  wechat convert_to_openid [USER_ID] # userid转换成openid
419
+ wechat convert_to_userid [OPENID] # openid转换成userid
418
420
  wechat custom_image [OPENID, IMAGE_PATH] # 发送图片客服消息
419
421
  wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # 发送音乐客服消息
420
422
  wechat custom_news [OPENID, NEWS_YAML_PATH] # 发送图文客服消息
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://travis-ci.org/Eric-Guo/wechat.svg)](https://travis-ci.org/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
1
+ WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.org/gems/wechat) [![Build Status](https://travis-ci.com/Eric-Guo/wechat.svg)](https://travis-ci.com/github/Eric-Guo/wechat) [![Maintainability](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/maintainability)](https://codeclimate.com/github/Eric-Guo/wechat/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/12885358487c13e91e00/test_coverage)](https://codeclimate.com/github/Eric-Guo/wechat/test_coverage)
2
2
  ======
3
3
 
4
4
  [![Join the chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Eric-Guo/wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -7,7 +7,7 @@ WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.or
7
7
 
8
8
  [Wechat](http://www.wechat.com/) is a Chinese multi-purpose messaging, social media and mobile payment app developed by Tencent. It was first released in 2011, and by 2018 it was one of the world's largest standalone mobile apps by monthly active users, with over 1 billion monthly active users (902 million daily active users). (According to [wiki](https://en.wikipedia.org/wiki/WeChat))
9
9
 
10
- WeChat gem helps Rails developers integrate [WeChat Official Accounts Platform](https://mp.weixin.qq.com/) and [Wechat Enterprise](https://qy.weixin.qq.com) easily, including features:
10
+ WeChat gem helps Rails developers integrate [WeChat Official Accounts Platform](https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html) or [Wechat mini program](https://developers.weixin.qq.com/miniprogram/dev/framework/) easily, including features:
11
11
 
12
12
  - [Sending message](http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF) API(can be both accessed via console or rails server)
13
13
  - [Receiving message](http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%E4%B8%8E%E4%BA%8B%E4%BB%B6)(rails server is required to be running)
@@ -430,6 +430,7 @@ Wechat Public Account commands:
430
430
  wechat user_group [OPEN_ID] # 查询用户所在分组
431
431
  wechat user_update_remark [OPEN_ID, REMARK] # 设置备注名
432
432
  wechat users # 关注者列表
433
+ wechat wxa_msg_sec_check [CONTENT] # 检查一段文本是否含有违法违规内容。
433
434
  wechat wxacode_download [WXA_CODE_PIC_PATH, PATH, WIDTH] # 下载小程序码
434
435
  wechat clear_quota # 接口调用次数清零
435
436
  ```
@@ -447,6 +448,7 @@ Wechat Enterprise Account commands:
447
448
  wechat callbackip # 获取微信服务器IP地址
448
449
  wechat clear_quota # 接口调用次数清零
449
450
  wechat convert_to_openid [USER_ID] # userid转换成openid
451
+ wechat convert_to_userid [OPENID] # openid转换成userid
450
452
  wechat custom_image [OPENID, IMAGE_PATH] # 发送图片客服消息
451
453
  wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL] # 发送音乐客服消息
452
454
  wechat custom_news [OPENID, NEWS_YAML_PATH] # 发送图文客服消息
data/bin/wechat CHANGED
@@ -187,6 +187,11 @@ class App < Thor
187
187
  puts wechat_api.convert_to_openid(userid)
188
188
  end
189
189
 
190
+ desc 'convert_to_userid [OPENID]', 'openid转换成userid'
191
+ def convert_to_userid(openid)
192
+ puts wechat_api.convert_to_userid(openid)
193
+ end
194
+
190
195
  desc 'agent_list', '获取应用概况列表'
191
196
  def agent_list
192
197
  r = wechat_api.agent_list
@@ -225,6 +230,11 @@ class App < Thor
225
230
  puts 'WXA Code File downloaded'
226
231
  end
227
232
 
233
+ desc 'wxa_msg_sec_check [CONTENT]', '检查一段文本是否含有违法违规内容。'
234
+ def wxa_msg_sec_check(content)
235
+ puts wechat_api.wxa_msg_sec_check(content)
236
+ end
237
+
228
238
  desc 'media_uploadnews [MPNEWS_YAML_PATH]', '上传图文消息素材'
229
239
  def media_uploadnews(mpnews_yaml_path)
230
240
  mpnew = YAML.load(File.read(mpnews_yaml_path))
@@ -38,25 +38,29 @@ module ActionController
38
38
  self.trusted_domain_fullname = opts[:trusted_domain_fullname] || cfg.trusted_domain_fullname
39
39
  self.oauth2_cookie_duration = opts[:oauth2_cookie_duration] || cfg.oauth2_cookie_duration.to_i.seconds
40
40
  self.timeout = opts[:timeout] || cfg.timeout
41
- self.skip_verify_ssl = if opts.key?(:skip_verify_ssl)
42
- opts[:skip_verify_ssl]
43
- else
44
- cfg.skip_verify_ssl
45
- end
41
+ self.qcloud_token_lifespan = opts[:qcloud_token_lifespan] || cfg.qcloud_token_lifespan
42
+ self.skip_verify_ssl = opts.key?(:skip_verify_ssl) ? opts[:skip_verify_ssl] : cfg.skip_verify_ssl
46
43
 
47
44
  return Wechat.api if account == :default && opts.empty?
48
45
 
49
46
  access_token = opts[:access_token] || cfg.access_token
50
47
  jsapi_ticket = opts[:jsapi_ticket] || cfg.jsapi_ticket
48
+ qcloud_env = opts[:qcloud_env] || cfg.qcloud_env
49
+ qcloud_token = opts[:qcloud_token] || cfg.qcloud_token
51
50
 
52
- if corpid.present?
53
- corpsecret = opts[:corpsecret] || cfg.corpsecret
54
- Wechat::CorpApi.new(corpid, corpsecret, access_token, \
55
- agentid, timeout, skip_verify_ssl, jsapi_ticket)
51
+ api_type = opts[:type] || cfg.type
52
+ secret = corpid.present? ? opts[:corpsecret] || cfg.corpsecret : opts[:secret] || cfg.secret
53
+
54
+ get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_env, qcloud_token, qcloud_token_lifespan)
55
+ end
56
+
57
+ def get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_env, qcloud_token, qcloud_token_lifespan)
58
+ if api_type && api_type.to_sym == :mp
59
+ Wechat::MpApi.new(appid, secret, access_token, timeout, skip_verify_ssl, jsapi_ticket, qcloud_env, qcloud_token, qcloud_token_lifespan)
60
+ elsif corpid.present?
61
+ Wechat::CorpApi.new(corpid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket)
56
62
  else
57
- secret = opts[:secret] || cfg.secret
58
- Wechat::Api.new(appid, secret, access_token, \
59
- timeout, skip_verify_ssl, jsapi_ticket)
63
+ Wechat::Api.new(appid, secret, access_token, timeout, skip_verify_ssl, jsapi_ticket)
60
64
  end
61
65
  end
62
66
  end
@@ -35,7 +35,7 @@ class WechatConfig < ActiveRecord::Base
35
35
  errors.add(:corpsecret, 'cannot be nil when corpid is set') if self[:corpsecret].blank?
36
36
  errors.add(:agentid, 'cannot be nil when corpid is set') if self[:agentid].blank?
37
37
  else
38
- errors[:base] << 'Either appid or corpid must be set'
38
+ errors.add(:base, 'Either appid or corpid must be set')
39
39
  end
40
40
  end
41
41
  end
data/lib/wechat.rb CHANGED
@@ -16,9 +16,12 @@ module Wechat
16
16
  autoload :ControllerApi, 'wechat/controller_api'
17
17
 
18
18
  class AccessTokenExpiredError < StandardError; end
19
+
19
20
  class InvalidCredentialError < StandardError; end
21
+
20
22
  class ResponseError < StandardError
21
23
  attr_reader :error_code
24
+
22
25
  def initialize(errcode, errmsg)
23
26
  @error_code = errcode
24
27
  super "#{errmsg}(#{error_code})"
@@ -47,7 +50,7 @@ module Wechat
47
50
  decrypted_data = Base64.decode64(encrypted_data)
48
51
  JSON.parse(cipher.update(decrypted_data) + cipher.final)
49
52
  rescue StandardError => e
50
- { 'errcode': 41003, 'errmsg': e.message }
53
+ { errcode: 41003, errmsg: e.message }
51
54
  end
52
55
  end
53
56
 
data/lib/wechat/api.rb CHANGED
@@ -8,6 +8,14 @@ require 'wechat/concern/common'
8
8
 
9
9
  module Wechat
10
10
  class Api < ApiBase
11
+ def initialize(appid, secret, token_file, timeout, skip_verify_ssl, jsapi_ticket_file)
12
+ super()
13
+ @client = HttpClient.new(Wechat::Api::API_BASE, timeout, skip_verify_ssl)
14
+ @access_token = Token::PublicAccessToken.new(@client, appid, secret, token_file)
15
+ @jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
16
+ @qcloud = nil
17
+ end
18
+
11
19
  include Concern::Common
12
20
 
13
21
  def template_message_send(message)
@@ -2,13 +2,14 @@
2
2
 
3
3
  module Wechat
4
4
  class ApiBase
5
- attr_reader :access_token, :client, :jsapi_ticket
5
+ attr_reader :access_token, :client, :jsapi_ticket, :qcloud
6
6
 
7
7
  API_BASE = 'https://api.weixin.qq.com/cgi-bin/'
8
8
  MP_BASE = 'https://mp.weixin.qq.com/cgi-bin/'
9
- WXA_BASE = 'https://api.weixin.qq.com/wxa/'
9
+ WXA_BASE = 'https://api.weixin.qq.com/wxa/'
10
10
  OAUTH2_BASE = 'https://api.weixin.qq.com/sns/'
11
11
  DATACUBE_BASE = 'https://api.weixin.qq.com/datacube/'
12
+ TCB_BASE = 'https://api.weixin.qq.com/tcb/'
12
13
  QYAPI_BASE = 'https://qyapi.weixin.qq.com/cgi-bin/'
13
14
 
14
15
  def callbackip
@@ -9,9 +9,16 @@ module Wechat
9
9
  token_file = options[:token_file] || c.access_token.presence || '/var/tmp/wechat_access_token'
10
10
  js_token_file = options[:js_token_file] || c.jsapi_ticket.presence || '/var/tmp/wechat_jsapi_ticket'
11
11
  type = options[:type] || c.type
12
+
12
13
  if c.appid && c.secret && token_file.present?
13
- wx_class = type == 'mp' ? Wechat::MpApi : Wechat::Api
14
- wx_class.new(c.appid, c.secret, token_file, c.timeout, c.skip_verify_ssl, js_token_file)
14
+ if type == 'mp'
15
+ qcloud_env = options[:qcloud_env] || c.qcloud_env
16
+ qcloud_token_file = options[:qcloud_token_file] || c.qcloud_token_file.presence || '/var/tmp/qcloud_access_token'
17
+ qcloud_token_lifespan = options[:qcloud_token_lifespan] || c.qcloud_token_lifespan
18
+ Wechat::MpApi.new(c.appid, c.secret, token_file, c.timeout, c.skip_verify_ssl, js_token_file, qcloud_env, qcloud_token_file, qcloud_token_lifespan)
19
+ else
20
+ Wechat::Api.new(c.appid, c.secret, token_file, c.timeout, c.skip_verify_ssl, js_token_file)
21
+ end
15
22
  elsif c.corpid && c.corpsecret && token_file.present?
16
23
  Wechat::CorpApi.new(c.corpid, c.corpsecret, token_file, c.agentid, c.timeout, c.skip_verify_ssl, js_token_file)
17
24
  else
@@ -46,11 +53,13 @@ module Wechat
46
53
  configs.each do |_, cfg|
47
54
  cfg[:access_token] ||= Rails.root.try(:join, 'tmp/access_token').try(:to_path)
48
55
  cfg[:jsapi_ticket] ||= Rails.root.try(:join, 'tmp/jsapi_ticket').try(:to_path)
56
+ cfg[:qcloud_token] ||= Rails.root.try(:join, 'tmp/qcloud_token').try(:to_path)
49
57
  end
50
58
  end
51
59
 
52
60
  configs.each do |_, cfg|
53
61
  cfg[:timeout] ||= 20
62
+ cfg[:qcloud_token_lifespan] ||= 7200
54
63
  cfg[:have_session_class] = class_exists?('WechatSession')
55
64
  cfg[:oauth2_cookie_duration] ||= 1.hour
56
65
  end
@@ -135,6 +144,9 @@ module Wechat
135
144
  skip_verify_ssl: ENV['WECHAT_SKIP_VERIFY_SSL'],
136
145
  encoding_aes_key: ENV['WECHAT_ENCODING_AES_KEY'],
137
146
  jsapi_ticket: ENV['WECHAT_JSAPI_TICKET'],
147
+ qcloud_env: ENV['WECHAT_QCLOUD_ENV'],
148
+ qcloud_token_file: ENV['WECHAT_QCLOUD_TOKEN'],
149
+ qcloud_token_lifespan: ENV['WECHAT_QCLOUD_TOKEN_LIFESPAN'],
138
150
  trusted_domain_fullname: ENV['WECHAT_TRUSTED_DOMAIN_FULLNAME'] }
139
151
  { default: value }
140
152
  end
data/lib/wechat/cipher.rb CHANGED
@@ -10,7 +10,7 @@ module Wechat
10
10
  cipher.encrypt
11
11
 
12
12
  cipher.padding = 0
13
- key_data = Base64.decode64(encoding_aes_key + '=')
13
+ key_data = Base64.decode64("#{encoding_aes_key}=")
14
14
  cipher.key = key_data
15
15
  cipher.iv = [key_data].pack('H*')
16
16
 
@@ -22,7 +22,7 @@ module Wechat
22
22
  cipher.decrypt
23
23
 
24
24
  cipher.padding = 0
25
- key_data = Base64.decode64(encoding_aes_key + '=')
25
+ key_data = Base64.decode64("#{encoding_aes_key}=")
26
26
  cipher.key = key_data
27
27
  cipher.iv = [key_data].pack('H*')
28
28
 
@@ -43,7 +43,7 @@ module Wechat
43
43
  msg = decode_padding(msg)
44
44
  msg_len = msg[16, 4].reverse.unpack1('V')
45
45
  content = msg[20, msg_len]
46
- app_id = msg[(20 + msg_len)..-1]
46
+ app_id = msg[(msg_len + 20)..-1]
47
47
 
48
48
  [content, app_id]
49
49
  end
@@ -3,12 +3,6 @@
3
3
  module Wechat
4
4
  module Concern
5
5
  module Common
6
- def initialize(appid, secret, token_file, timeout, skip_verify_ssl, jsapi_ticket_file)
7
- @client = HttpClient.new(Wechat::Api::API_BASE, timeout, skip_verify_ssl)
8
- @access_token = Token::PublicAccessToken.new(@client, appid, secret, token_file)
9
- @jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
10
- end
11
-
12
6
  def groups
13
7
  get 'groups/get'
14
8
  end
@@ -106,6 +100,10 @@ module Wechat
106
100
  post 'wxaapp/createwxaqrcode', JSON.generate(path: path, width: width)
107
101
  end
108
102
 
103
+ def wxa_msg_sec_check(content)
104
+ post 'msg_sec_check', JSON.generate(content: content), base: Wechat::Api::WXA_BASE
105
+ end
106
+
109
107
  def menu
110
108
  get 'menu/get'
111
109
  end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wechat
4
+ module Concern
5
+ module Qcloud
6
+ def invoke_cloud_function(function_name, post_body_params)
7
+ post 'invokecloudfunction', JSON.generate(post_body_params), params: { env: qcloud.qcloud_env, name: function_name }, base: Wechat::Api::TCB_BASE
8
+ end
9
+
10
+ def qdb_migrate_import(collection_name, file_path, file_type: Wechat::Qcloud::FILE_TYPE_JSON, stop_on_error: false, conflict_mode: Wechat::Qcloud::CONFLICT_MODE_UPSERT)
11
+ import_params_hash = { env: qcloud.qcloud_env,
12
+ collection_name: collection_name,
13
+ file_path: file_path,
14
+ file_type: file_type,
15
+ stop_on_error: stop_on_error,
16
+ conflict_mode: conflict_mode }
17
+ post 'databasemigrateimport', JSON.generate(import_params_hash), base: Wechat::Api::TCB_BASE
18
+ end
19
+
20
+ def qdb_migrate_export(query, file_path, file_type: Wechat::Qcloud::FILE_TYPE_JSON)
21
+ export_params_hash = { env: qcloud.qcloud_env,
22
+ file_path: file_path,
23
+ file_type: file_type,
24
+ query: query }
25
+ post 'databasemigrateexport', JSON.generate(export_params_hash), base: Wechat::Api::TCB_BASE
26
+ end
27
+
28
+ def qdb_migrate_query(job_id)
29
+ query_info_hash = { env: qcloud.qcloud_env,
30
+ job_id: job_id }
31
+
32
+ post 'databasemigratequeryinfo', JSON.generate(query_info_hash), base: Wechat::Api::TCB_BASE
33
+ end
34
+
35
+ def qdb_update_index(collection_name, create_indexes: [], drop_indexes: [])
36
+ update_index_params_hash = { env: qcloud.qcloud_env,
37
+ collection_name: collection_name,
38
+ create_indexes: create_indexes,
39
+ drop_indexes: drop_indexes }
40
+ post 'updateindex', JSON.generate(update_index_params_hash), base: Wechat::Api::TCB_BASE
41
+ end
42
+
43
+ def qdb_collection_add(collection_name)
44
+ collection_add_params_hash = { env: qcloud.qcloud_env,
45
+ collection_name: collection_name }
46
+ post 'databasecollectionadd', JSON.generate(collection_add_params_hash), base: Wechat::Api::TCB_BASE
47
+ end
48
+
49
+ def qdb_collection_delete(collection_name)
50
+ collection_delete_params_hash = { env: qcloud.qcloud_env,
51
+ collection_name: collection_name }
52
+ post 'databasecollectiondelete', JSON.generate(collection_delete_params_hash), base: Wechat::Api::TCB_BASE
53
+ end
54
+
55
+ def qdb_collections(limit: 10, offset: 0)
56
+ get_collections_params_hash = { env: qcloud.qcloud_env,
57
+ limit: limit,
58
+ offset: offset }
59
+ post 'databasecollectionget', JSON.generate(get_collections_params_hash), base: Wechat::Api::TCB_BASE
60
+ end
61
+
62
+ def qdb_add(add_query)
63
+ post 'databaseadd', JSON.generate(env: qcloud.qcloud_env, query: add_query), base: Wechat::Api::TCB_BASE
64
+ end
65
+
66
+ def qdb_delete(delete_query)
67
+ post 'databasedelete', JSON.generate(env: qcloud.qcloud_env, query: delete_query), base: Wechat::Api::TCB_BASE
68
+ end
69
+
70
+ def qdb_update(update_query)
71
+ post 'databaseupdate', JSON.generate(env: qcloud.qcloud_env, query: update_query), base: Wechat::Api::TCB_BASE
72
+ end
73
+
74
+ def qdb_query(query)
75
+ post 'databasequery', JSON.generate(env: qcloud.qcloud_env, query: query), base: Wechat::Api::TCB_BASE
76
+ end
77
+
78
+ def qdb_aggregate(aggregate_query)
79
+ post 'databaseaggregate', JSON.generate(env: qcloud.qcloud_env, query: aggregate_query), base: Wechat::Api::TCB_BASE
80
+ end
81
+
82
+ def qdb_count(count_query)
83
+ post 'databasecount', JSON.generate(env: qcloud.qcloud_env, query: count_query), base: Wechat::Api::TCB_BASE
84
+ end
85
+
86
+ def tcb_delete_files(fileid_list)
87
+ post 'batchdeletefile', JSON.generate(env: qcloud.qcloud_env, fileid_list: fileid_list), base: Wechat::Api::TCB_BASE
88
+ end
89
+
90
+ def tcb_download_files(file_list)
91
+ post 'batchdownloadfile', JSON.generate(env: qcloud.qcloud_env, file_list: file_list), base: Wechat::Api::TCB_BASE
92
+ end
93
+
94
+ def tcb_preflight_upload_file(q_path)
95
+ post 'uploadfile', JSON.generate(env: qcloud.qcloud_env, path: q_path), base: Wechat::Api::TCB_BASE
96
+ end
97
+
98
+ def tcb_do_upload_file(q_path, upload_url, signature, x_cos_security_token, x_cos_meta_fileid, file)
99
+ form_file = file.is_a?(HTTP::FormData::File) ? file : HTTP::FormData::File.new(file)
100
+ form_data = HTTP::FormData.create({ key: q_path,
101
+ Signature: signature,
102
+ "x-cos-security-token": x_cos_security_token,
103
+ 'x-cos-meta-fileid': x_cos_meta_fileid,
104
+ file: form_file })
105
+ client.httprb.post(upload_url, form: form_data, ssl_context: client.ssl_context)
106
+ end
107
+
108
+ def tcb_upload_file(q_path, file)
109
+ res = tcb_preflight_upload_file(q_path)
110
+ tcb_do_upload_file(q_path, res['url'], res['authorization'], res['token'], res['cos_file_id'], file)
111
+ res
112
+ end
113
+ end
114
+ end
115
+ end
@@ -5,7 +5,7 @@ module Wechat
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
- attr_accessor :wechat_api_client, :wechat_cfg_account, :token, :appid, :corpid, :agentid, :encrypt_mode, :timeout,
8
+ attr_accessor :wechat_api_client, :wechat_cfg_account, :token, :appid, :corpid, :agentid, :encrypt_mode, :timeout, :qcloud_token_lifespan,
9
9
  :skip_verify_ssl, :encoding_aes_key, :trusted_domain_fullname, :oauth2_cookie_duration
10
10
  end
11
11
 
@@ -10,10 +10,12 @@ module Wechat
10
10
  attr_reader :agentid
11
11
 
12
12
  def initialize(appid, secret, token_file, agentid, timeout, skip_verify_ssl, jsapi_ticket_file)
13
+ super()
13
14
  @client = HttpClient.new(QYAPI_BASE, timeout, skip_verify_ssl)
14
15
  @access_token = Token::CorpAccessToken.new(@client, appid, secret, token_file)
15
16
  @agentid = agentid
16
17
  @jsapi_ticket = Ticket::CorpJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
18
+ @qcloud = nil
17
19
  end
18
20
 
19
21
  def agent_list
@@ -45,6 +47,10 @@ module Wechat
45
47
  post 'user/convert_to_openid', JSON.generate(userid: userid, agentid: agentid)
46
48
  end
47
49
 
50
+ def convert_to_userid(openid)
51
+ post 'user/convert_to_userid', JSON.generate(openid: openid)
52
+ end
53
+
48
54
  def invite_user(userid)
49
55
  post 'invite/send', JSON.generate(userid: userid)
50
56
  end
@@ -90,7 +96,7 @@ module Wechat
90
96
  end
91
97
 
92
98
  def department_update(departmentid, name = nil, parentid = nil, order = nil)
93
- post 'department/update', JSON.generate({ id: departmentid, name: name, parentid: parentid, order: order }.reject { |_k, v| v.nil? })
99
+ post 'department/update', JSON.generate({ id: departmentid, name: name, parentid: parentid, order: order }.compact)
94
100
  end
95
101
 
96
102
  def department(departmentid = 1)
@@ -24,7 +24,7 @@ module Wechat
24
24
  else
25
25
  controller.request.original_url
26
26
  end
27
- page_url = page_url.split('#').first if ios?
27
+ page_url = page_url.split('#').first
28
28
  js_hash = api.jsapi_ticket.signature(page_url)
29
29
 
30
30
  config_js = <<~WECHAT_CONFIG_JS
@@ -39,11 +39,5 @@ module Wechat
39
39
  WECHAT_CONFIG_JS
40
40
  javascript_tag config_js, type: 'application/javascript'
41
41
  end
42
-
43
- private
44
-
45
- def ios?
46
- controller.request.user_agent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
47
- end
48
42
  end
49
43
  end
@@ -14,7 +14,7 @@ module Wechat
14
14
  HTTP.timeout(:global, write: timeout, connect: timeout, read: timeout)
15
15
  end
16
16
  @ssl_context = OpenSSL::SSL::SSLContext.new
17
- @ssl_context.ssl_version = :TLSv1_2
17
+ @ssl_context.ssl_version = 'TLSv1_2'
18
18
  @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE if skip_verify_ssl
19
19
  end
20
20
 
@@ -77,12 +77,12 @@ module Wechat
77
77
  def parse_response(response, as_type)
78
78
  content_type = response.headers[:content_type]
79
79
  parse_as = {
80
- %r{^application\/json} => :json,
81
- %r{^image\/.*} => :file,
82
- %r{^audio\/.*} => :file,
83
- %r{^voice\/.*} => :file,
84
- %r{^text\/html} => :xml,
85
- %r{^text\/plain} => :probably_json
80
+ %r{^application/json} => :json,
81
+ %r{^image/.*} => :file,
82
+ %r{^audio/.*} => :file,
83
+ %r{^voice/.*} => :file,
84
+ %r{^text/html} => :xml,
85
+ %r{^text/plain} => :probably_json
86
86
  }.each_with_object([]) { |match, memo| memo << match[1] if content_type =~ match[0] }.first || as_type || :text
87
87
 
88
88
  # try to parse response as json, fallback to user-specified format or text if failed
@@ -32,6 +32,7 @@ module Wechat
32
32
 
33
33
  class ArticleBuilder
34
34
  attr_reader :items
35
+
35
36
  delegate :count, to: :items
36
37
  def initialize
37
38
  @items = []
@@ -40,14 +41,14 @@ module Wechat
40
41
 
41
42
  class NewsArticleBuilder < ArticleBuilder
42
43
  def item(title: 'title', description: nil, pic_url: nil, url: nil)
43
- items << { Title: title, Description: description, PicUrl: pic_url, Url: url }.reject { |_k, v| v.nil? }
44
+ items << { Title: title, Description: description, PicUrl: pic_url, Url: url }.compact
44
45
  end
45
46
  end
46
47
 
47
48
  class MpNewsArticleBuilder < ArticleBuilder
48
49
  def item(thumb_media_id:, title:, content:, author: nil, content_source_url: nil, digest: nil, show_cover_pic: '0')
49
50
  items << { Thumb_Media_ID: thumb_media_id, Author: author, Title: title, ContentSourceUrl: content_source_url,
50
- Content: content, Digest: digest, ShowCoverPic: show_cover_pic }.reject { |_k, v| v.nil? }
51
+ Content: content, Digest: digest, ShowCoverPic: show_cover_pic }.compact
51
52
  end
52
53
  end
53
54
 
@@ -168,7 +169,7 @@ module Wechat
168
169
  items = article.items
169
170
  else
170
171
  items = collection.collect do |item|
171
- camelize_hash_keys(item.symbolize_keys.slice(:title, :description, :pic_url, :url).reject { |_k, v| v.nil? })
172
+ camelize_hash_keys(item.symbolize_keys.slice(:title, :description, :pic_url, :url).compact)
172
173
  end
173
174
  end
174
175
 
@@ -183,7 +184,7 @@ module Wechat
183
184
  items = article.items
184
185
  else
185
186
  items = collection.collect do |item|
186
- camelize_hash_keys(item.symbolize_keys.slice(:thumb_media_id, :title, :content, :author, :content_source_url, :digest, :show_cover_pic).reject { |_k, v| v.nil? })
187
+ camelize_hash_keys(item.symbolize_keys.slice(:thumb_media_id, :title, :content, :author, :content_source_url, :digest, :show_cover_pic).compact)
187
188
  end
188
189
  end
189
190
 
data/lib/wechat/mp_api.rb CHANGED
@@ -4,11 +4,22 @@ require 'wechat/api_base'
4
4
  require 'wechat/http_client'
5
5
  require 'wechat/token/public_access_token'
6
6
  require 'wechat/ticket/public_jsapi_ticket'
7
+ require 'wechat/qcloud/token'
7
8
  require 'wechat/concern/common'
9
+ require 'wechat/concern/qcloud'
8
10
 
9
11
  module Wechat
10
12
  class MpApi < ApiBase
13
+ def initialize(appid, secret, token_file, timeout, skip_verify_ssl, jsapi_ticket_file, qcloud_env, qcloud_token_file, qcloud_token_lifespan)
14
+ super()
15
+ @client = HttpClient.new(Wechat::Api::API_BASE, timeout, skip_verify_ssl)
16
+ @access_token = Token::PublicAccessToken.new(@client, appid, secret, token_file)
17
+ @jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
18
+ @qcloud = Qcloud::Token.new(@client, @access_token, qcloud_env, qcloud_token_file, qcloud_token_lifespan)
19
+ end
20
+
11
21
  include Concern::Common
22
+ include Concern::Qcloud
12
23
 
13
24
  def template_message_send(message)
14
25
  post 'message/wxopen/template/send', message.to_json, content_type: :json
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wechat
4
+ module Qcloud
5
+ FILE_TYPE_JSON = 1
6
+ FILE_TYPE_CSV = 2
7
+ CONFLICT_MODE_INSERT = 1
8
+ CONFLICT_MODE_UPSERT = 2
9
+
10
+ class Token
11
+ attr_reader :client, :access_token, :qcloud_env, :qcloud_token_file, :qcloud_token_lifespan, :qcloud_token, :qcloud_token_expired_time
12
+
13
+ def initialize(client, access_token, qcloud_env, qcloud_token_file, lifespan)
14
+ @client = client
15
+ @access_token = access_token
16
+ @qcloud_env = qcloud_env
17
+ @qcloud_token_file = qcloud_token_file
18
+ @qcloud_token_lifespan = lifespan
19
+ @random_generator = Random.new
20
+ end
21
+
22
+ def token(tries = 2)
23
+ # Possible two worker running, one worker refresh ticket, other unaware, so must read every time
24
+ read_qcloud_token_from_store
25
+ refresh if remain_life_seconds < @random_generator.rand(30..3 * 60)
26
+ qcloud_token
27
+ rescue AccessTokenExpiredError
28
+ access_token.refresh
29
+ retry unless (tries -= 1).zero?
30
+ end
31
+
32
+ def refresh
33
+ data = client.post('getqcloudtoken', JSON.generate(lifespan: qcloud_token_lifespan), base: ::Wechat::ApiBase::TCB_BASE, params: { access_token: access_token.token })
34
+ write_qcloud_token_to_store(data)
35
+ read_qcloud_token_from_store
36
+ end
37
+
38
+ protected
39
+
40
+ def read_qcloud_token_from_store
41
+ td = read_qcloud_token
42
+ @qcloud_token_expired_time = td.fetch('qcloud_token_expired_time').to_i
43
+ @qcloud_token = td.fetch('token') # return qcloud_token same time
44
+ rescue JSON::ParserError, Errno::ENOENT, KeyError, TypeError
45
+ refresh
46
+ end
47
+
48
+ def write_qcloud_token_to_store(qcloud_token_hash)
49
+ qcloud_token_hash['qcloud_token_expired_time'] = qcloud_token_hash.delete('expired_time')
50
+ write_qcloud_token(qcloud_token_hash)
51
+ end
52
+
53
+ def read_qcloud_token
54
+ JSON.parse(File.read(qcloud_token_file))
55
+ end
56
+
57
+ def write_qcloud_token(qcloud_token_hash)
58
+ File.write(qcloud_token_file, qcloud_token_hash.to_json)
59
+ end
60
+
61
+ def remain_life_seconds
62
+ qcloud_token_expired_time - Time.now.to_i
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'English'
4
+ require 'rexml/document'
4
5
  require 'wechat/signature'
5
6
 
6
7
  module Wechat
@@ -145,9 +146,10 @@ module Wechat
145
146
  next
146
147
  end
147
148
 
148
- if condition.is_a? Regexp
149
+ case condition
150
+ when Regexp
149
151
  memo[:scoped] ||= [responder] + $LAST_MATCH_INFO.captures if value =~ condition
150
- elsif value == condition
152
+ when value
151
153
  memo[:scoped] ||= [responder, value]
152
154
  end
153
155
  end
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wechat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.9
4
+ version: 0.12.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skinnyworm
8
8
  - Eric Guo
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain:
12
12
  - |
13
13
  -----BEGIN CERTIFICATE-----
14
14
  MIIEQDCCAqigAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBplcmlj
15
- Lmd1b2N6L0RDPWdtYWlsL0RDPWNvbTAeFw0xOTA4MzAwODIzMTVaFw0yMDA4Mjkw
16
- ODIzMTVaMCUxIzAhBgNVBAMMGmVyaWMuZ3VvY3ovREM9Z21haWwvREM9Y29tMIIB
17
- ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA2ZlFyUImo53jN4+1Kk6cyGts
18
- LcT2x+i3G4mvZeqrZFCyhgWHJ04oAsfKBLCLRmspRsUuDQ3GQ8P5tH9oTduu55qy
19
- ohflwuuffJHwsJYJEQ4hykJSCQ8gd4qj8WrhAmNo15ujq6mjGXPRBtZltR142kKE
20
- o1tUYtc4Fr3oIAh65m62ZC2kJ5GATLYQ+U3JiiHWga8iJ8KSHbrzhM4N3ppaeYxD
21
- wk6Lwk2OyppO9Iiv9Ad2BEFFd2s7mvYtaMGPWYK2fYTUuq6yKupg3CppX3ttq+bN
22
- Ejx6dXn4RwYmATfc/Iv4aVU8lZS9HABqmProgkmi5vE2AAW1rQihm2ACm9VGlX+B
23
- J2uIIWFJC56+TmkyqcBM87ztRxFlNLJe1G2S2TZ/qhAyWfoSEDA9eW6OUsb6qvnz
24
- PHFPo/Vgq9BEoYMItUsEoJHdmLBjzhiccQx2XWAhZrBREpH20jIC/ereVGRpAeVf
25
- kYdFgW84K+lL9XTt9QJNM08YM/mFcpaGq4/2YbbLAgMBAAGjezB5MAkGA1UdEwQC
26
- MAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQdvlZDewUSWN/OWf9bTuDHHc5r+TAf
15
+ Lmd1b2N6L0RDPWdtYWlsL0RDPWNvbTAeFw0yMDA5MDIwNDUzMjFaFw0yMTA5MDIw
16
+ NDUzMjFaMCUxIzAhBgNVBAMMGmVyaWMuZ3VvY3ovREM9Z21haWwvREM9Y29tMIIB
17
+ ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwSfWr5RlUBlv9OuNgmxjPwhU
18
+ 7eoT/m7K5h0PzUaue+dtno4WqjodoCPHF6r9hh8Ys0h1VAPu3sobH2gNaL18M0CY
19
+ bmq+ik6LgH5tX2E6c2BmhMuURt2y1YvIwvx0dDOlEXll9J8ZVqGyo3Rm9AIblA3/
20
+ w/V5VJGCj3XY6iipNkHHDlSWSYeD2mNr0wJW8EAUFFcyRddpotxR9Es8JwUpXdj8
21
+ Bc5a/OWxKvzqLVlu76zYRYuZ41+3gWNxYF9OPnp55sNtsboGh5LJSdXZOs5+gMw9
22
+ gEW/KsP4GSMlqBT7SQEO5EH3qjp3aatHaMT8Fq9h3AnNESQMubMWtlPqEYyrYkli
23
+ wr8A8SGiX3rCkNG0cc4zVsagtXm4csbSeaIjLV57LA2sKngI4/kw55UYlloAtGPh
24
+ qNEqsPLbN/RkyS1zQjf14mQBpBt3SdxnT7YDSPIYiAPTtLuThcy3Flgh6cDX1RH7
25
+ FQPZJzQ7pSb/3Edj+VBaYhpo+y4ySLxx9DOLfm6lAgMBAAGjezB5MAkGA1UdEwQC
26
+ MAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBRWBfZurpq8AmvpfBq7eSA0ivhotDAf
27
27
  BgNVHREEGDAWgRRlcmljLmd1b2N6QGdtYWlsLmNvbTAfBgNVHRIEGDAWgRRlcmlj
28
- Lmd1b2N6QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAkS8q1uex/jWTHtYi
29
- 6Rgv8hZugwpFCwGPb9i4VgSSA1qkfsFhNxQji1xcpo8hYlH6zW9L6CGC9BU4n9R2
30
- iyuuvtHVnxt5i6u39fIw0dIHJdtswSXZ6Kq58RP1Lg1nbmXX0zHz1fXp+DXL7NoJ
31
- bBHL9Oy6jps/Lz8fIanPIZ6iT/akA7Mts94v1F9dyeA3IIJVptvmuGFC9PexX4TJ
32
- fZ/qmk93C6KEOGEQ0zJzjnKjRZT0KOnJxbpB6/4Xvr+SrTb0yx20s+YWWa28pb0C
33
- gNr4HHRfhmqxoTKvM4Mm9oJSBO/ENi5zfLwvwOWRuriMuDGYmKCdwmn4Y9asgYS4
34
- 2febpVoh2LTA7GDc1VJOKhxisQ2OtYpcTR503eGyIrnS4NGs+B0rXOB7pEX+VOju
35
- 2Gz/SZ1dgCkJpJU45GNrhatKx3kyg8eC5IHekNrEvJNJqPl0VdRIs/GtUkQyk+np
36
- 3kTPkfLMsAZznXo3bzMe0V5TB4+a7pFEK1nN/htWrOVkIi/3
28
+ Lmd1b2N6QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAJ1tLpEqCXma9fFeU
29
+ l6N4tEDrwYVxdbkXgOScUZBsagNlEM9vvskygivKu8AV8ffdtsg9OAuhdfAjPjX+
30
+ GvGnmuoweHFTsIrOhNryqFDgvkufBczmFLOskjRuzt4NoBNgge8+xoNo+N9o/0jz
31
+ GZi69Dth2i92rffuEzyFbfA9xzkjL+uSqJRJVDP5UbIWGnQ99M4GfplJZWRkmoX9
32
+ 5Ek/ZVhzEz6kdZuZErloYKqjWWvFHUFAYmJd3fqKpb468yTIaL4bl4aUl2+xLdyK
33
+ fPI/ZWGy2uNjffzbrhJ+Ti6qAdubkJoMIqrfbrFV1ew2Bxkp/93etXVNjAgHNmu1
34
+ o3VAf3sbhnj33jAri7JYx/1MhAcJXlvpKxX9QnYouxU/RgzBF7oqcT0dJ2jWUnAI
35
+ spvOK5/LPXWX6ZGc2SR8SH/s7ftYH2EkeM1VUbtemow08NdgCwJ4IG+fRQ9dcrJ+
36
+ L9TbpLHvVrCe1w8duMqNeUmqj+M1iC/5Zst2vIe14QcOTuAh
37
37
  -----END CERTIFICATE-----
38
- date: 2020-04-29 00:00:00.000000000 Z
38
+ date: 2021-03-15 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: activesupport
@@ -105,20 +105,34 @@ dependencies:
105
105
  - - ">="
106
106
  - !ruby/object:Gem::Version
107
107
  version: '0'
108
+ - !ruby/object:Gem::Dependency
109
+ name: rexml
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ type: :runtime
116
+ prerelease: false
117
+ version_requirements: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
108
122
  - !ruby/object:Gem::Dependency
109
123
  name: rubocop
110
124
  requirement: !ruby/object:Gem::Requirement
111
125
  requirements:
112
126
  - - "~>"
113
127
  - !ruby/object:Gem::Version
114
- version: '0.74'
128
+ version: '1.0'
115
129
  type: :development
116
130
  prerelease: false
117
131
  version_requirements: !ruby/object:Gem::Requirement
118
132
  requirements:
119
133
  - - "~>"
120
134
  - !ruby/object:Gem::Version
121
- version: '0.74'
135
+ version: '1.0'
122
136
  - !ruby/object:Gem::Dependency
123
137
  name: rails
124
138
  requirement: !ruby/object:Gem::Requirement
@@ -139,14 +153,14 @@ dependencies:
139
153
  requirements:
140
154
  - - "~>"
141
155
  - !ruby/object:Gem::Version
142
- version: '3.6'
156
+ version: '4.0'
143
157
  type: :development
144
158
  prerelease: false
145
159
  version_requirements: !ruby/object:Gem::Requirement
146
160
  requirements:
147
161
  - - "~>"
148
162
  - !ruby/object:Gem::Version
149
- version: '3.6'
163
+ version: '4.0'
150
164
  - !ruby/object:Gem::Dependency
151
165
  name: sqlite3
152
166
  requirement: !ruby/object:Gem::Requirement
@@ -195,12 +209,14 @@ files:
195
209
  - lib/wechat/api_loader.rb
196
210
  - lib/wechat/cipher.rb
197
211
  - lib/wechat/concern/common.rb
212
+ - lib/wechat/concern/qcloud.rb
198
213
  - lib/wechat/controller_api.rb
199
214
  - lib/wechat/corp_api.rb
200
215
  - lib/wechat/helpers.rb
201
216
  - lib/wechat/http_client.rb
202
217
  - lib/wechat/message.rb
203
218
  - lib/wechat/mp_api.rb
219
+ - lib/wechat/qcloud/token.rb
204
220
  - lib/wechat/responder.rb
205
221
  - lib/wechat/signature.rb
206
222
  - lib/wechat/ticket/corp_jsapi_ticket.rb
@@ -213,23 +229,23 @@ homepage: https://github.com/Eric-Guo/wechat
213
229
  licenses:
214
230
  - MIT
215
231
  metadata: {}
216
- post_install_message:
232
+ post_install_message:
217
233
  rdoc_options: []
218
234
  require_paths:
219
235
  - lib
220
236
  required_ruby_version: !ruby/object:Gem::Requirement
221
237
  requirements:
222
- - - "~>"
238
+ - - ">="
223
239
  - !ruby/object:Gem::Version
224
- version: '2.3'
240
+ version: '2.4'
225
241
  required_rubygems_version: !ruby/object:Gem::Requirement
226
242
  requirements:
227
243
  - - ">="
228
244
  - !ruby/object:Gem::Version
229
245
  version: '0'
230
246
  requirements: []
231
- rubygems_version: 3.1.2
232
- signing_key:
247
+ rubygems_version: 3.2.14
248
+ signing_key:
233
249
  specification_version: 4
234
250
  summary: DSL for wechat message handling and API
235
251
  test_files: []
metadata.gz.sig CHANGED
@@ -1,3 +1,5 @@
1
- *?+䫏0����Y�ń���{x��E9�`n�� r�����ae9n���ªP�_��4��֛tU��i21-�O�%FP���Kx��V`l����Z�6ҽ�~H���#�ZyK
2
- <��m
3
- pn��ֲ�~��
1
+ LDl�u~��U�IzGj��qխf#Jz��T>j]��$�:�"P��Zj,�����;�;e��Z�w�;��O�ҕ�PLы��&엯�d�El�6�
2
+ ��� `+��T�.�G�D*�hPd���ԳB�%gi��F�J̰�Z���y�A ��P="�y�
3
+ �숏��'�)�u�.,h�5�
4
+ ��Dmo/��J����Ji�����k���5�{7����v�ܮ��fY���[�$��eh�7�.P�Wx���^:+�P��s!��<��.Ѭ4��"��[z����M�Ω� �{�z�mZ9�L&]�B�Od'�p}���'
5
+ s�� �b��&���� �-�g� �(�Ҫ�ο�Pq��ڌo5����8X�|�oz^+��Sr�