wechat 0.11.7 → 0.12.1

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: ed7c19916af2b008eeb90cbd140261806457a679ac04fd1d7cafc741b5414494
4
- data.tar.gz: a16c5a69bbd32d54263cf3fc15207a0c3278384f75239c3dc94fefa3952b8d68
3
+ metadata.gz: f7dfe45f7c68aafa5b96a2a3178ae2108f9989bb5594b6ae35d1e7dcc358219a
4
+ data.tar.gz: 25a51c65de855682ec12ee332241d9acd47c8cc8c2376995c8d8f0512825e899
5
5
  SHA512:
6
- metadata.gz: 76379f62522cf5eff64c0772a127a7e9ed4be8ceed0eba6710acc47f641c20404bccf039ac6383d0e61148e38171edb704b02f28c4a325dd68f79b83e9ba3dc7
7
- data.tar.gz: da56c9242149a5a636975ad59bec0f1cb735b2d25ca2c06fec6125a972127f16c68dbdb2f114d208be3cc91a55cc582ea03dcce74360c67aa5a6865adde79642
6
+ metadata.gz: '080ada4dbb3191ed4d10d51d4cef85de0cfc469af61f636ee99b03be92e487060fa454a37ef54a8386d77d1ebede360d2819c64d59f0d1ca2a202ba199e1a31e'
7
+ data.tar.gz: f3482024b4e35f91924c384ca27819748341444047c135362552b460ccf15243fcd5fd1c896e0c15eb00e392aa73ce1c750854b78e6e0c52af0176482e4939cb
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.12.1 (released at 28/12/2020)
4
+
5
+ * Support Ruby 3.0.
6
+ * Qcloud_token support.
7
+ * CRUD of tencent cloud DB for miniapp
8
+ * TCB storage API support.
9
+ * Set default branch to *main*.
10
+
11
+ ## v0.11.11 (released at 09/13/2020)
12
+
13
+ * FIX: fix_load_controller_wechat not support MP type, by @Msms-NJ #281
14
+
15
+ ## v0.11.10 (released at 09/02/2020)
16
+
17
+ * ADD: Wechat::MpApi.wxa_msg_sec_check.
18
+
19
+ ## v0.11.9 (released at 04/29/2020)
20
+
21
+ * CHG: upgrade ssl_version to 1.2 by @paicha #276
22
+
23
+ ## v0.11.8 (released at 03/09/2020)
24
+
25
+ * ADD: Wechat::CorpApi.news_message_send
26
+ * FIX: Wechat API Change material/get_material. reported by @0000sir #275
27
+
3
28
  ## v0.11.7 (released at 11/15/2019)
4
29
 
5
30
  * ADD: Wechat::MpApi.subscribe_message_send. by @paicha #271
@@ -3,7 +3,7 @@ WeChat [![Gem Version](https://badge.fury.io/rb/wechat.svg)](https://rubygems.or
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服务器)
@@ -360,7 +360,7 @@ Wechat Public Account commands:
360
360
  wechat group_delete [GROUP_ID] # 删除分组
361
361
  wechat group_update [GROUP_ID, NEW_GROUP_NAME] # 修改分组名
362
362
  wechat groups # 查询所有分组
363
- wechat material [MEDIA_ID, PATH] # 永久媒体下载
363
+ wechat material_get [MEDIA_ID, PATH] # 永久媒体下载
364
364
  wechat material_add [MEDIA_TYPE, PATH] # 永久媒体上传
365
365
  wechat material_count # 获取永久素材总数
366
366
  wechat material_delete [MEDIA_ID] # 删除永久素材
@@ -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
 
data/README.md CHANGED
@@ -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)
@@ -391,7 +391,7 @@ Wechat Public Account commands:
391
391
  wechat group_delete [GROUP_ID] # 删除分组
392
392
  wechat group_update [GROUP_ID, NEW_GROUP_NAME] # 修改分组名
393
393
  wechat groups # 查询所有分组
394
- wechat material [MEDIA_ID, PATH] # 永久媒体下载
394
+ wechat material_get [MEDIA_ID, PATH] # 永久媒体下载
395
395
  wechat material_add [MEDIA_TYPE, PATH] # 永久媒体上传
396
396
  wechat material_count # 获取永久素材总数
397
397
  wechat material_delete [MEDIA_ID] # 删除永久素材
@@ -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
  ```
data/bin/wechat CHANGED
@@ -225,6 +225,11 @@ class App < Thor
225
225
  puts 'WXA Code File downloaded'
226
226
  end
227
227
 
228
+ desc 'wxa_msg_sec_check [CONTENT]', '检查一段文本是否含有违法违规内容。'
229
+ def wxa_msg_sec_check(content)
230
+ puts wechat_api.wxa_msg_sec_check(content)
231
+ end
232
+
228
233
  desc 'media_uploadnews [MPNEWS_YAML_PATH]', '上传图文消息素材'
229
234
  def media_uploadnews(mpnews_yaml_path)
230
235
  mpnew = YAML.load(File.read(mpnews_yaml_path))
@@ -389,9 +394,9 @@ class App < Thor
389
394
  puts wechat_api.media_uploadimg(image_path)
390
395
  end
391
396
 
392
- desc 'material [MEDIA_ID, PATH]', '永久媒体下载'
393
- def material(media_id, path)
394
- tmp_file = wechat_api.material(media_id)
397
+ desc 'material_get [MEDIA_ID, PATH]', '永久媒体下载'
398
+ def material_get(media_id, path)
399
+ tmp_file = wechat_api.get_material(media_id)
395
400
  FileUtils.mv(tmp_file.path, path)
396
401
  puts 'File downloaded'
397
402
  end
@@ -38,25 +38,28 @@ 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_token = opts[:qcloud_token] || cfg.qcloud_token
51
49
 
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)
50
+ api_type = opts[:type] || cfg.type
51
+ secret = corpid.present? ? opts[:corpsecret] || cfg.corpsecret : opts[:secret] || cfg.secret
52
+
53
+ get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_token, qcloud_token_lifespan)
54
+ end
55
+
56
+ def get_wechat_api(api_type, corpid, appid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket, qcloud_token, qcloud_token_lifespan)
57
+ if api_type && api_type.to_sym == :mp
58
+ Wechat::MpApi.new(appid, secret, access_token, timeout, skip_verify_ssl, jsapi_ticket, qcloud_token, qcloud_token_lifespan)
59
+ elsif corpid.present?
60
+ Wechat::CorpApi.new(corpid, secret, access_token, agentid, timeout, skip_verify_ssl, jsapi_ticket)
56
61
  else
57
- secret = opts[:secret] || cfg.secret
58
- Wechat::Api.new(appid, secret, access_token, \
59
- timeout, skip_verify_ssl, jsapi_ticket)
62
+ Wechat::Api.new(appid, secret, access_token, timeout, skip_verify_ssl, jsapi_ticket)
60
63
  end
61
64
  end
62
65
  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
@@ -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})"
@@ -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
@@ -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
 
@@ -41,7 +41,7 @@ module Wechat
41
41
 
42
42
  def unpack(msg)
43
43
  msg = decode_padding(msg)
44
- msg_len = msg[16, 4].reverse.unpack('V')[0]
44
+ msg_len = msg[16, 4].reverse.unpack1('V')
45
45
  content = msg[20, msg_len]
46
46
  app_id = msg[(20 + msg_len)..-1]
47
47
 
@@ -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
@@ -133,7 +131,13 @@ module Wechat
133
131
  end
134
132
 
135
133
  def material(media_id)
136
- get 'material/get', params: { media_id: media_id }, as: :file
134
+ ActiveSupport::Deprecation.warn('material is deprecated. use get_material instead.')
135
+
136
+ post 'material/get_material', JSON.generate(media_id: media_id), as: :file
137
+ end
138
+
139
+ def get_material(media_id)
140
+ post 'material/get_material', JSON.generate(media_id: media_id), as: :file
137
141
  end
138
142
 
139
143
  def material_count
@@ -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
@@ -90,7 +92,7 @@ module Wechat
90
92
  end
91
93
 
92
94
  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? })
95
+ post 'department/update', JSON.generate({ id: departmentid, name: name, parentid: parentid, order: order }.compact)
94
96
  end
95
97
 
96
98
  def department(departmentid = 1)
@@ -155,7 +157,13 @@ module Wechat
155
157
  end
156
158
 
157
159
  def material(media_id)
158
- get 'material/get', params: { media_id: media_id, agentid: agentid }, as: :file
160
+ ActiveSupport::Deprecation.warn('material is deprecated. use get_material instead.')
161
+
162
+ post 'material/get_material', JSON.generate(media_id: media_id), params: { agentid: agentid }, as: :file
163
+ end
164
+
165
+ def get_material(media_id)
166
+ post 'material/get_material', JSON.generate(media_id: media_id), params: { agentid: agentid }, as: :file
159
167
  end
160
168
 
161
169
  def material_add(type, file)
@@ -170,6 +178,14 @@ module Wechat
170
178
  post 'message/send', Message.to(userid).text(message).agent_id(agentid).to_json, content_type: :json
171
179
  end
172
180
 
181
+ def news_message_send(userid, title, description, link_url, pic_url)
182
+ post 'message/send', Message.to(userid).news([{ title: title,
183
+ description: description,
184
+ url: link_url,
185
+ pic_url: pic_url }])
186
+ .agent_id(agentid).to_json, content_type: :json
187
+ end
188
+
173
189
  def custom_message_send(message)
174
190
  post 'message/send', message.is_a?(Wechat::Message) ? message.agent_id(agentid).to_json : JSON.generate(message.merge(agent_id: agentid)), content_type: :json
175
191
  end
@@ -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
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
 
@@ -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.7
4
+ version: 0.12.1
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: 2019-11-15 00:00:00.000000000 Z
38
+ date: 2020-12-28 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.0.6
232
- signing_key:
247
+ rubygems_version: 3.2.3
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
Binary file