wechat 0.11.8 → 0.12.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +25 -1
- data/README-CN.md +4 -2
- data/README.md +4 -2
- data/bin/wechat +10 -0
- data/lib/action_controller/wechat_responder.rb +15 -12
- data/lib/generators/wechat/templates/app/models/wechat_config.rb +1 -1
- data/lib/wechat.rb +4 -1
- data/lib/wechat/api.rb +8 -0
- data/lib/wechat/api_base.rb +3 -2
- data/lib/wechat/api_loader.rb +14 -2
- data/lib/wechat/cipher.rb +4 -4
- data/lib/wechat/concern/common.rb +4 -6
- data/lib/wechat/concern/qcloud.rb +115 -0
- data/lib/wechat/controller_api.rb +1 -1
- data/lib/wechat/corp_api.rb +7 -1
- data/lib/wechat/helpers.rb +1 -7
- data/lib/wechat/http_client.rb +7 -7
- data/lib/wechat/message.rb +5 -4
- data/lib/wechat/mp_api.rb +11 -0
- data/lib/wechat/qcloud/token.rb +66 -0
- data/lib/wechat/responder.rb +4 -2
- metadata +49 -33
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9e5954c81e1297f27d583c6e0df58714d5ab47489bef715ddacc4fb8dd23839
|
4
|
+
data.tar.gz: 1753d132e3207da06427214efa61b498ba06ea5ca23b7b6f5a6f74a0fb235932
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 945c4b637ba60360c1447765a0e6e4b87f121d0a5dac1aecfc0a74c8fd92f365d273a7ea56ab30ebe67ad07d1791dfa2444685f81b8d7957d0046e14a4f0dd36
|
7
|
+
data.tar.gz: dc760927b6a6f5836af1ff3e2e9f1b722c87db80994b8c8b0f0ed83cc154ebdb4395670cb4108ef71ff865f3df784f1fe3ca622d14f6484b47cb23321a9cb2cb
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## v0.
|
3
|
+
## v0.12.2 (released at 3/3/2021)
|
4
|
+
|
5
|
+
* New convert_to_userid API
|
6
|
+
|
7
|
+
## v0.12.1 (released at 28/12/2020)
|
8
|
+
|
9
|
+
* Support Ruby 3.0.
|
10
|
+
* Qcloud_token support.
|
11
|
+
* CRUD of tencent cloud DB for miniapp
|
12
|
+
* TCB storage API support.
|
13
|
+
* Set default branch to *main*.
|
14
|
+
|
15
|
+
## v0.11.11 (released at 09/13/2020)
|
16
|
+
|
17
|
+
* FIX: fix_load_controller_wechat not support MP type, by @Msms-NJ #281
|
18
|
+
|
19
|
+
## v0.11.10 (released at 09/02/2020)
|
20
|
+
|
21
|
+
* ADD: Wechat::MpApi.wxa_msg_sec_check.
|
22
|
+
|
23
|
+
## v0.11.9 (released at 04/29/2020)
|
24
|
+
|
25
|
+
* CHG: upgrade ssl_version to 1.2 by @paicha #276
|
26
|
+
|
27
|
+
## v0.11.8 (released at 03/09/2020)
|
4
28
|
|
5
29
|
* ADD: Wechat::CorpApi.news_message_send
|
6
30
|
* FIX: Wechat API Change material/get_material. reported by @0000sir #275
|
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.
|
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://
|
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.
|
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://
|
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,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.
|
42
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
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
|
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
|
-
{
|
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)
|
data/lib/wechat/api_base.rb
CHANGED
@@ -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
|
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
|
data/lib/wechat/api_loader.rb
CHANGED
@@ -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
|
-
|
14
|
-
|
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
|
|
@@ -41,9 +41,9 @@ module Wechat
|
|
41
41
|
|
42
42
|
def unpack(msg)
|
43
43
|
msg = decode_padding(msg)
|
44
|
-
msg_len = msg[16, 4].reverse.
|
44
|
+
msg_len = msg[16, 4].reverse.unpack1('V')
|
45
45
|
content = msg[20, msg_len]
|
46
|
-
app_id = msg[(
|
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
|
|
data/lib/wechat/corp_api.rb
CHANGED
@@ -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 }.
|
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)
|
data/lib/wechat/helpers.rb
CHANGED
@@ -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
|
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
|
data/lib/wechat/http_client.rb
CHANGED
@@ -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 =
|
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
|
81
|
-
%r{^image
|
82
|
-
%r{^audio
|
83
|
-
%r{^voice
|
84
|
-
%r{^text
|
85
|
-
%r{^text
|
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
|
data/lib/wechat/message.rb
CHANGED
@@ -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 }.
|
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 }.
|
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).
|
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).
|
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
|
data/lib/wechat/responder.rb
CHANGED
@@ -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
|
-
|
149
|
+
case condition
|
150
|
+
when Regexp
|
149
151
|
memo[:scoped] ||= [responder] + $LAST_MATCH_INFO.captures if value =~ condition
|
150
|
-
|
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.
|
4
|
+
version: 0.12.2
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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:
|
38
|
+
date: 2021-03-03 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
|
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
|
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: '
|
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: '
|
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.
|
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.
|
232
|
-
signing_key:
|
247
|
+
rubygems_version: 3.2.12
|
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
|