wechat 0.17.7 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +11 -0
- data/README-CN.md +2 -2
- data/README.md +2 -2
- data/lib/action_controller/wechat_responder.rb +9 -8
- data/lib/generators/wechat/templates/app/models/wechat_config.rb +5 -2
- data/lib/generators/wechat/templates/db/config_migration.rb.erb +2 -0
- data/lib/wechat/api.rb +4 -4
- data/lib/wechat/api_config.rb +15 -0
- data/lib/wechat/api_loader.rb +20 -16
- data/lib/wechat/concern/common.rb +0 -6
- data/lib/wechat/concern/qcloud.rb +1 -1
- data/lib/wechat/corp_api.rb +4 -10
- data/lib/wechat/http_client.rb +37 -28
- data/lib/wechat/message.rb +13 -9
- data/lib/wechat/mp_api.rb +4 -4
- data/lib/wechat/network_setting.rb +2 -3
- data/lib/wechat/qcloud/token.rb +1 -1
- data/lib/wechat/ticket/jsapi_base.rb +3 -3
- data/lib/wechat/token/access_token_base.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +16 -18
- 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: 8862a096490e208b18609027a14e80d12b386dcd86094065e4412856012ec3db
|
4
|
+
data.tar.gz: a71e7b18973fab14ff351b04e840c534ea6229ff59c98d0cc2deee93587237ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0dc2fab306d761d1a887478c2eb3d355064fa0c3a18bc5a91df6fb426eed5fe4d73073738d0011ca15e0b1a8042035fcb53b0d57937b9749c31d8efd94cb704e
|
7
|
+
data.tar.gz: 83eb3e8c604000a515888c0bca6f7d059de49f07fd691c67dd6a0a5bc1262a8fd1758a672f6244b54f3771bd6f591593b0b03b3d660c3a1c030397dd8ee87a0e
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v1.0.1 (released at 2025-07-09)
|
4
|
+
|
5
|
+
* Fix after introduce httpx, status method not available for HTTPX::ErrorResponse bug
|
6
|
+
* Some Google Jules Refactor
|
7
|
+
|
8
|
+
## v1.0.0 (released at 2025-05-17)
|
9
|
+
|
10
|
+
* WECHAT_PROXY_URL should be writen with port, like `export WECHAT_PROXY_URL=http://127.0.0.1:6152`, since WECHAT_PROXY_PORT removed.
|
11
|
+
* Replace http with httpx, [reason](https://honeyryderchuck.gitlab.io/2023/10/15/state-of-ruby-http-clients-use-httpx.html)
|
12
|
+
* Feat: add account_type to WechatConfig. by @leepood #324
|
13
|
+
|
3
14
|
## v0.17.7 (released at 2025-03-02)
|
4
15
|
|
5
16
|
* Adding ostruct into its gemspec. Fix #323
|
data/README-CN.md
CHANGED
@@ -227,6 +227,7 @@ test:
|
|
227
227
|
environment | 字串 | 必填。配置对应的运行环境,一般有:`production`、`development`、`test`。比如 `production` 配置仅在生产环境有效。默认为 `development`。
|
228
228
|
account | 字串 | 必填。自定义的微信账户名称。同一 `environment` 下,账户名称不允许重复。
|
229
229
|
enabled | 布尔 | 必填。配置是否生效。默认 `true`。
|
230
|
+
account_type | 字串 | 非必填。当前只支持`mp`,表示小程序。
|
230
231
|
appid | 字串 | 公众号 id ,此字段和 `corpid` 两者必填其一。
|
231
232
|
secret | 字串 | 公众号相关配置。当公众号 `appid` 存在时必填。
|
232
233
|
corpid | 字串 | 企业号 id。此字段和 `appid` 两者必填其一。
|
@@ -896,6 +897,5 @@ end
|
|
896
897
|
|
897
898
|
## 已知问题
|
898
899
|
|
899
|
-
* 企业微信接受菜单消息时,Wechat 腾讯服务器无法解析部分域名,请使用 iP 绑定回调 URL,用户的普通消息目前不受影响。
|
900
900
|
* 企业微信全量覆盖成员使用的 CSV 通讯录格式,直接将下载的模板导入[是不工作的](http://qydev.weixin.qq.com/qa/index.php?qa=13978),必须使用 Excel 打开,然后另存为 CSV 格式才会变成合法格式。
|
901
|
-
*
|
901
|
+
* 在开发模式上使用外部反响代理 https 回调,可能需要设置 `trusted_domain_fullname` 为 https,否则会导致 JS-SDK 签名失效。
|
data/README.md
CHANGED
@@ -254,6 +254,7 @@ Attribute | Type | Annotation
|
|
254
254
|
---- | ---- | ----
|
255
255
|
environment | string | Required. Environment of account configuration. Typical values are: `production`, `development` and `test`. For example, a `production` config will only be available in `production`. Default to `development`.
|
256
256
|
account | string | Required. Custom wechat account name. Account names must be unique within each environment.
|
257
|
+
account_type | string | account type, only support `mp` which is short for `mini program` currently
|
257
258
|
enabled | boolean | Required. Whether this configuration is activated. Default to `true`.
|
258
259
|
appid | string | Public account id. Either this attribute or `corpid` must be specified.
|
259
260
|
secret | string | Public account configuration. Required when `appid` exists.
|
@@ -928,6 +929,5 @@ end
|
|
928
929
|
|
929
930
|
## Known Issues
|
930
931
|
|
931
|
-
* Sometimes, enterprise account can not receive the menu message due to Tencent server unable to resolve DNS, so using IP as a callback URL is more stable, but it never happens for user sent text messages.
|
932
932
|
* Enterprise batch "replace users" uses a CSV format file, but if you are using the downloaded template directly, it's [not working](http://qydev.weixin.qq.com/qa/index.php?qa=13978), must open the CSV file in Excel first, then save as CSV format again, seems Tencent only supports Excel "Save as CSV" file format.
|
933
|
-
*
|
933
|
+
* Using an external feedback proxy HTTPS callback in development mode may require setting `trusted_domain_fullname` to HTTPS, otherwise the JS-SDK signature will be invalid.
|
@@ -41,7 +41,6 @@ module ActionController
|
|
41
41
|
self.skip_verify_ssl = opts.key?(:skip_verify_ssl) ? opts[:skip_verify_ssl] : cfg.skip_verify_ssl
|
42
42
|
|
43
43
|
proxy_url = opts.key?(:proxy_url) ? opts[:proxy_url] : cfg.proxy_url
|
44
|
-
proxy_port = opts.key?(:proxy_port) ? opts[:proxy_port] : cfg.proxy_port
|
45
44
|
proxy_username = opts.key?(:proxy_username) ? opts[:proxy_username] : cfg.proxy_username
|
46
45
|
proxy_password = opts.key?(:proxy_password) ? opts[:proxy_password] : cfg.proxy_password
|
47
46
|
|
@@ -56,18 +55,20 @@ module ActionController
|
|
56
55
|
api_type = opts[:type] || cfg.type
|
57
56
|
secret = corpid.present? ? opts[:corpsecret] || cfg.corpsecret : opts[:secret] || cfg.secret
|
58
57
|
|
59
|
-
network_setting = Wechat::NetworkSetting.new(timeout, skip_verify_ssl, proxy_url,
|
58
|
+
network_setting = Wechat::NetworkSetting.new(timeout, skip_verify_ssl, proxy_url, proxy_username, proxy_password)
|
59
|
+
# access_token is token_file, jsapi_ticket is jsapi_ticket_file
|
60
|
+
api_config = Wechat::ApiConfig.new(corpid.presence || appid, secret, access_token, jsapi_ticket, network_setting)
|
60
61
|
qcloud_setting = Wechat::Qcloud::Setting.new(qcloud_env, qcloud_token, qcloud_token_lifespan)
|
61
|
-
get_wechat_api(api_type,
|
62
|
+
get_wechat_api(api_type, api_config, agentid, qcloud_setting)
|
62
63
|
end
|
63
64
|
|
64
|
-
def get_wechat_api(api_type,
|
65
|
+
def get_wechat_api(api_type, api_config, agentid, qcloud_setting)
|
65
66
|
if api_type && api_type.to_sym == :mp
|
66
|
-
Wechat::MpApi.new(
|
67
|
-
elsif
|
68
|
-
Wechat::CorpApi.new(
|
67
|
+
Wechat::MpApi.new(api_config, qcloud_setting)
|
68
|
+
elsif api_config.appid.present? && agentid.present? # Assuming corpid is now in api_config.appid for CorpApi
|
69
|
+
Wechat::CorpApi.new(api_config, agentid)
|
69
70
|
else
|
70
|
-
Wechat::Api.new(
|
71
|
+
Wechat::Api.new(api_config)
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
@@ -9,10 +9,11 @@ class WechatConfig < ActiveRecord::Base
|
|
9
9
|
validates :access_token, presence: true
|
10
10
|
validates :jsapi_ticket, presence: true
|
11
11
|
validates :encoding_aes_key, presence: { if: :encrypt_mode? }
|
12
|
+
validates :account_type, inclusion: { in: %w[mp] }, if: -> { account_type.present? }
|
12
13
|
|
13
14
|
validate :app_config_is_valid
|
14
15
|
|
15
|
-
ATTRIBUTES_TO_REMOVE = %w[environment account created_at updated_at enabled].freeze
|
16
|
+
ATTRIBUTES_TO_REMOVE = %w[environment account created_at updated_at enabled account_type].freeze
|
16
17
|
|
17
18
|
def self.get_all_configs(environment)
|
18
19
|
WechatConfig.where(environment: environment, enabled: true).each_with_object({}) do |config, hash|
|
@@ -21,7 +22,9 @@ class WechatConfig < ActiveRecord::Base
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def build_config_hash
|
24
|
-
as_json(except: ATTRIBUTES_TO_REMOVE)
|
25
|
+
config_hash = as_json(except: ATTRIBUTES_TO_REMOVE)
|
26
|
+
config_hash[:type] = account_type if account_type.present?
|
27
|
+
config_hash
|
25
28
|
end
|
26
29
|
|
27
30
|
private
|
@@ -5,6 +5,8 @@ class CreateWechatConfigs < ActiveRecord::Migration<%= migration_version %>
|
|
5
5
|
t.string :environment, null: false, default: 'development'
|
6
6
|
# account name
|
7
7
|
t.string :account, null: false
|
8
|
+
# account type, "mp" is short for mini program
|
9
|
+
t.string :account_type
|
8
10
|
# whether this config is activated
|
9
11
|
t.boolean :enabled, default: true
|
10
12
|
|
data/lib/wechat/api.rb
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Wechat
|
4
4
|
class Api < ApiBase
|
5
|
-
def initialize(
|
5
|
+
def initialize(api_config, record = nil)
|
6
6
|
super()
|
7
|
-
@client = HttpClient.new(Wechat::Api::API_BASE, network_setting)
|
8
|
-
@access_token = Token::PublicAccessToken.new(@client, appid, secret, token_file, record)
|
9
|
-
@jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
|
7
|
+
@client = HttpClient.new(Wechat::Api::API_BASE, api_config.network_setting)
|
8
|
+
@access_token = Token::PublicAccessToken.new(@client, api_config.appid, api_config.secret, api_config.token_file, record)
|
9
|
+
@jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, api_config.jsapi_ticket_file)
|
10
10
|
@qcloud = nil
|
11
11
|
end
|
12
12
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wechat
|
4
|
+
class ApiConfig
|
5
|
+
attr_reader :appid, :secret, :token_file, :jsapi_ticket_file, :network_setting
|
6
|
+
|
7
|
+
def initialize(appid, secret, token_file, jsapi_ticket_file, network_setting)
|
8
|
+
@appid = appid
|
9
|
+
@secret = secret
|
10
|
+
@token_file = token_file
|
11
|
+
@jsapi_ticket_file = jsapi_ticket_file
|
12
|
+
@network_setting = network_setting
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/wechat/api_loader.rb
CHANGED
@@ -12,21 +12,26 @@ module Wechat
|
|
12
12
|
js_token_file = options[:js_token_file] || c.jsapi_ticket.presence || '/var/tmp/wechat_jsapi_ticket'
|
13
13
|
type = options[:type] || c.type
|
14
14
|
|
15
|
-
network_setting = Wechat::NetworkSetting.new(c.timeout, c.skip_verify_ssl, c.proxy_url, c.
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
15
|
+
network_setting = Wechat::NetworkSetting.new(c.timeout, c.skip_verify_ssl, c.proxy_url, c.proxy_username, c.proxy_password)
|
16
|
+
|
17
|
+
current_appid = c.corpid.presence || c.appid
|
18
|
+
current_secret = c.corpsecret.presence || c.secret
|
19
|
+
|
20
|
+
unless current_appid && current_secret && token_file.present?
|
21
|
+
raise 'Need create ~/.wechat.yml with wechat appid and secret or corpid and corpsecret, or running at rails root folder so wechat can read config/wechat.yml'
|
22
|
+
end
|
23
|
+
|
24
|
+
api_config = Wechat::ApiConfig.new(current_appid, current_secret, token_file, js_token_file, network_setting)
|
25
|
+
if type == 'mp'
|
26
|
+
qcloud_env = options[:qcloud_env] || c.qcloud_env
|
27
|
+
qcloud_token_file = options[:qcloud_token_file] || c.qcloud_token_file.presence || '/var/tmp/qcloud_access_token'
|
28
|
+
qcloud_token_lifespan = options[:qcloud_token_lifespan] || c.qcloud_token_lifespan
|
29
|
+
qcloud_setting = Wechat::Qcloud::Setting.new(qcloud_env, qcloud_token_file, qcloud_token_lifespan)
|
30
|
+
Wechat::MpApi.new(api_config, qcloud_setting)
|
31
|
+
elsif c.corpid.present? # CorpApi needs agentid
|
32
|
+
Wechat::CorpApi.new(api_config, c.agentid)
|
33
|
+
else # Regular Public Api
|
34
|
+
Wechat::Api.new(api_config)
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
@@ -166,7 +171,6 @@ module Wechat
|
|
166
171
|
timeout: ENV.fetch('WECHAT_TIMEOUT', nil),
|
167
172
|
skip_verify_ssl: ENV.fetch('WECHAT_SKIP_VERIFY_SSL', nil),
|
168
173
|
proxy_url: ENV.fetch('WECHAT_PROXY_URL', nil),
|
169
|
-
proxy_port: ENV.fetch('WECHAT_PROXY_PORT', nil),
|
170
174
|
proxy_username: ENV.fetch('WECHAT_PROXY_USERNAME', nil),
|
171
175
|
proxy_password: ENV.fetch('WECHAT_PROXY_PASSWORD', nil),
|
172
176
|
encoding_aes_key: ENV.fetch('WECHAT_ENCODING_AES_KEY', nil),
|
@@ -144,12 +144,6 @@ module Wechat
|
|
144
144
|
post 'menu/delconditional', JSON.generate(menuid: menuid)
|
145
145
|
end
|
146
146
|
|
147
|
-
def material(media_id)
|
148
|
-
ActiveSupport::Deprecation.new.warn('material is deprecated. use get_material instead.')
|
149
|
-
|
150
|
-
post 'material/get_material', JSON.generate(media_id: media_id), as: :file
|
151
|
-
end
|
152
|
-
|
153
147
|
def get_material(media_id)
|
154
148
|
post 'material/get_material', JSON.generate(media_id: media_id), as: :file
|
155
149
|
end
|
@@ -102,7 +102,7 @@ module Wechat
|
|
102
102
|
'x-cos-security-token': x_cos_security_token,
|
103
103
|
'x-cos-meta-fileid': x_cos_meta_fileid,
|
104
104
|
file: form_file })
|
105
|
-
client.
|
105
|
+
client.httpx.post(upload_url, form: form_data)
|
106
106
|
end
|
107
107
|
|
108
108
|
def tcb_upload_file(q_path, file)
|
data/lib/wechat/corp_api.rb
CHANGED
@@ -4,12 +4,12 @@ module Wechat
|
|
4
4
|
class CorpApi < ApiBase
|
5
5
|
attr_reader :agentid
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(api_config, agentid)
|
8
8
|
super()
|
9
|
-
@client = HttpClient.new(QYAPI_BASE, network_setting)
|
10
|
-
@access_token = Token::CorpAccessToken.new(@client, appid, secret, token_file)
|
9
|
+
@client = HttpClient.new(QYAPI_BASE, api_config.network_setting)
|
10
|
+
@access_token = Token::CorpAccessToken.new(@client, api_config.appid, api_config.secret, api_config.token_file)
|
11
11
|
@agentid = agentid
|
12
|
-
@jsapi_ticket = Ticket::CorpJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
|
12
|
+
@jsapi_ticket = Ticket::CorpJsapiTicket.new(@client, @access_token, api_config.jsapi_ticket_file)
|
13
13
|
@qcloud = nil
|
14
14
|
end
|
15
15
|
|
@@ -170,12 +170,6 @@ module Wechat
|
|
170
170
|
post 'material/batchget', JSON.generate(type: type, agentid: agentid, offset: offset, count: count)
|
171
171
|
end
|
172
172
|
|
173
|
-
def material(media_id)
|
174
|
-
ActiveSupport::Deprecation.new.warn('material is deprecated. use get_material instead.')
|
175
|
-
|
176
|
-
post 'material/get_material', JSON.generate(media_id: media_id), params: { agentid: agentid }, as: :file
|
177
|
-
end
|
178
|
-
|
179
173
|
def get_material(media_id)
|
180
174
|
post 'material/get_material', JSON.generate(media_id: media_id), params: { agentid: agentid }, as: :file
|
181
175
|
end
|
data/lib/wechat/http_client.rb
CHANGED
@@ -1,51 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'httpx'
|
4
4
|
|
5
5
|
module Wechat
|
6
6
|
class HttpClient
|
7
|
-
attr_reader :base, :
|
7
|
+
attr_reader :base, :httpx
|
8
8
|
|
9
9
|
def initialize(base, network_setting)
|
10
10
|
@base = base
|
11
|
-
@
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
unless network_setting.proxy_url.nil?
|
18
|
-
@httprb = @httprb.via(network_setting.proxy_url, network_setting.proxy_port.to_i, network_setting.proxy_username, network_setting.proxy_password)
|
11
|
+
@httpx = HTTPX.with(timeout: { connect_timeout: network_setting.timeout, request_timeout: network_setting.timeout })
|
12
|
+
|
13
|
+
if network_setting.proxy_url.present?
|
14
|
+
@httpx = @httpx.with_proxy(uri: network_setting.proxy_url,
|
15
|
+
username: network_setting.proxy_username,
|
16
|
+
password: network_setting.proxy_password)
|
19
17
|
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
@
|
19
|
+
return unless network_setting.skip_verify_ssl
|
20
|
+
|
21
|
+
@httpx = @httpx.with(ssl: { verify_mode: OpenSSL::SSL::VERIFY_NONE })
|
24
22
|
end
|
25
23
|
|
26
24
|
def get(path, get_header = {})
|
27
|
-
request(path, get_header) do |url,
|
28
|
-
params =
|
29
|
-
|
25
|
+
request(path, get_header) do |url, headers|
|
26
|
+
params = headers.delete(:params)
|
27
|
+
httpx.with(headers: headers)
|
28
|
+
.get(url, params: params)
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
33
32
|
def post(path, payload, post_header = {})
|
34
|
-
request(path, post_header) do |url,
|
35
|
-
params =
|
36
|
-
|
33
|
+
request(path, post_header) do |url, headers|
|
34
|
+
params = headers.delete(:params)
|
35
|
+
httpx.with(headers: headers)
|
36
|
+
.post(url, params: params, body: payload)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
def post_file(path, file, post_header = {})
|
41
|
-
request(path, post_header) do |url,
|
42
|
-
params =
|
41
|
+
request(path, post_header) do |url, headers|
|
42
|
+
params = headers.delete(:params)
|
43
43
|
form_file = file.is_a?(HTTP::FormData::File) ? file : HTTP::FormData::File.new(file)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
hack: 'X' }, # Existing here for http-form_data 1.0.1 handle single param improperly
|
48
|
-
ssl_context: ssl_context)
|
44
|
+
httpx.with(headers: headers)
|
45
|
+
.post(url, params: params,
|
46
|
+
form: { media: form_file })
|
49
47
|
end
|
50
48
|
end
|
51
49
|
|
@@ -57,7 +55,18 @@ module Wechat
|
|
57
55
|
header['Accept'] ||= 'application/json'
|
58
56
|
response = yield("#{url_base}#{path}", header)
|
59
57
|
|
60
|
-
|
58
|
+
# Error responses (network failures, DNS errors, etc.) are returned as
|
59
|
+
# `HTTPX::ErrorResponse` objects which **do not** implement `#status`.
|
60
|
+
# Attempting to access that method would raise a `NoMethodError`.
|
61
|
+
# Instead, surface the underlying error immediately so that callers can
|
62
|
+
# handle it using the existing error-handling flow.
|
63
|
+
if defined?(HTTPX::ErrorResponse) && response.is_a?(HTTPX::ErrorResponse)
|
64
|
+
# `response.error` returns the wrapped exception (e.g. Errno::ECONNREFUSED)
|
65
|
+
# Fallback to raising the response itself if no wrapped error exists.
|
66
|
+
raise(response.error || StandardError.new(response.inspect))
|
67
|
+
end
|
68
|
+
|
69
|
+
raise "Request not OK, response #{response}" if response.respond_to?(:status) && response.status != 200
|
61
70
|
|
62
71
|
parse_response(response, as || :json) do |parse_as, data|
|
63
72
|
break data unless parse_as == :json && data['errcode'].present?
|
@@ -80,7 +89,7 @@ module Wechat
|
|
80
89
|
end
|
81
90
|
|
82
91
|
def parse_response(response, as_type)
|
83
|
-
content_type = response.headers[
|
92
|
+
content_type = response.headers['content-type']
|
84
93
|
parse_as = {
|
85
94
|
%r{^application/json} => :json,
|
86
95
|
%r{^image/.*} => :file,
|
data/lib/wechat/message.rb
CHANGED
@@ -9,16 +9,16 @@ module Wechat
|
|
9
9
|
|
10
10
|
def to(to_users = '', towxname: nil, send_ignore_reprint: 0)
|
11
11
|
if towxname.present?
|
12
|
-
new(ToWxName: towxname, CreateTime: Time.now.to_i)
|
12
|
+
new(ToWxName: towxname, CreateTime: Time.zone.now.to_i)
|
13
13
|
elsif send_ignore_reprint == 1
|
14
|
-
new(ToUserName: to_users, CreateTime: Time.now.to_i, send_ignore_reprint: send_ignore_reprint)
|
14
|
+
new(ToUserName: to_users, CreateTime: Time.zone.now.to_i, send_ignore_reprint: send_ignore_reprint)
|
15
15
|
else
|
16
|
-
new(ToUserName: to_users, CreateTime: Time.now.to_i)
|
16
|
+
new(ToUserName: to_users, CreateTime: Time.zone.now.to_i)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
def to_party(party)
|
21
|
-
new(ToPartyName: party, CreateTime: Time.now.to_i)
|
21
|
+
new(ToPartyName: party, CreateTime: Time.zone.now.to_i)
|
22
22
|
end
|
23
23
|
|
24
24
|
def to_mass(tag_id: nil, send_ignore_reprint: 0)
|
@@ -65,7 +65,7 @@ module Wechat
|
|
65
65
|
Message.new(
|
66
66
|
ToUserName: message_hash[:FromUserName],
|
67
67
|
FromUserName: message_hash[:ToUserName],
|
68
|
-
CreateTime: Time.now.to_i,
|
68
|
+
CreateTime: Time.zone.now.to_i,
|
69
69
|
WechatSession: session
|
70
70
|
)
|
71
71
|
end
|
@@ -238,8 +238,14 @@ module Wechat
|
|
238
238
|
key = key.to_s
|
239
239
|
[TO_JSON_KEY_MAP[key] || (keep_camel_case_key ? key : key.downcase), value]
|
240
240
|
end
|
241
|
-
json_hash = json_hash.transform_keys(&:downcase).
|
241
|
+
json_hash = json_hash.transform_keys(&:downcase).slice(*TO_JSON_ALLOWED)
|
242
|
+
json_hash = transform_json_hash_by_msgtype(json_hash)
|
243
|
+
JSON.generate(json_hash)
|
244
|
+
end
|
245
|
+
|
246
|
+
private
|
242
247
|
|
248
|
+
def transform_json_hash_by_msgtype(json_hash)
|
243
249
|
case json_hash['msgtype']
|
244
250
|
when 'text'
|
245
251
|
json_hash['text'] = { 'content' => json_hash.delete('content') }
|
@@ -255,7 +261,7 @@ module Wechat
|
|
255
261
|
when 'template'
|
256
262
|
json_hash = { 'touser' => json_hash['touser'] }.merge!(json_hash['template'])
|
257
263
|
end
|
258
|
-
|
264
|
+
json_hash
|
259
265
|
end
|
260
266
|
|
261
267
|
def save_to!(model_class)
|
@@ -264,8 +270,6 @@ module Wechat
|
|
264
270
|
self
|
265
271
|
end
|
266
272
|
|
267
|
-
private
|
268
|
-
|
269
273
|
def camelize_hash_keys(hash)
|
270
274
|
deep_recursive(hash) { |key, value| [key.to_s.camelize.to_sym, value] }
|
271
275
|
end
|
data/lib/wechat/mp_api.rb
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Wechat
|
4
4
|
class MpApi < ApiBase
|
5
|
-
def initialize(
|
5
|
+
def initialize(api_config, qcloud_setting)
|
6
6
|
super()
|
7
|
-
@client = HttpClient.new(Wechat::Api::API_BASE, network_setting)
|
8
|
-
@access_token = Token::PublicAccessToken.new(@client, appid, secret, token_file)
|
9
|
-
@jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
|
7
|
+
@client = HttpClient.new(Wechat::Api::API_BASE, api_config.network_setting)
|
8
|
+
@access_token = Token::PublicAccessToken.new(@client, api_config.appid, api_config.secret, api_config.token_file)
|
9
|
+
@jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, api_config.jsapi_ticket_file)
|
10
10
|
@qcloud = Qcloud::Token.new(@client, @access_token, qcloud_setting)
|
11
11
|
end
|
12
12
|
|
@@ -2,13 +2,12 @@
|
|
2
2
|
|
3
3
|
module Wechat
|
4
4
|
class NetworkSetting
|
5
|
-
attr_reader :timeout, :skip_verify_ssl, :proxy_url, :
|
5
|
+
attr_reader :timeout, :skip_verify_ssl, :proxy_url, :proxy_username, :proxy_password
|
6
6
|
|
7
|
-
def initialize(timeout, skip_verify_ssl, proxy_url,
|
7
|
+
def initialize(timeout, skip_verify_ssl, proxy_url, proxy_username, proxy_password)
|
8
8
|
@timeout = timeout
|
9
9
|
@skip_verify_ssl = skip_verify_ssl
|
10
10
|
@proxy_url = proxy_url
|
11
|
-
@proxy_port = proxy_port
|
12
11
|
@proxy_username = proxy_username
|
13
12
|
@proxy_password = proxy_password
|
14
13
|
end
|
data/lib/wechat/qcloud/token.rb
CHANGED
@@ -41,7 +41,7 @@ module Wechat
|
|
41
41
|
def signature(url)
|
42
42
|
params = {
|
43
43
|
noncestr: SecureRandom.base64(16),
|
44
|
-
timestamp: Time.now.to_i,
|
44
|
+
timestamp: Time.zone.now.to_i,
|
45
45
|
jsapi_ticket: ticket,
|
46
46
|
url: url
|
47
47
|
}
|
@@ -65,7 +65,7 @@ module Wechat
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def write_ticket_to_store(ticket_hash)
|
68
|
-
ticket_hash['got_ticket_at'] = Time.now.to_i
|
68
|
+
ticket_hash['got_ticket_at'] = Time.zone.now.to_i
|
69
69
|
ticket_hash['ticket_expires_in'] = ticket_hash.delete('expires_in')
|
70
70
|
write_ticket(ticket_hash)
|
71
71
|
end
|
@@ -79,7 +79,7 @@ module Wechat
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def remain_life_seconds
|
82
|
-
ticket_life_in_seconds - (Time.now.to_i - got_ticket_at)
|
82
|
+
ticket_life_in_seconds - (Time.zone.now.to_i - got_ticket_at)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -35,7 +35,7 @@ module Wechat
|
|
35
35
|
def write_token_to_store(token_hash)
|
36
36
|
raise InvalidCredentialError unless token_hash.is_a?(Hash) && token_hash['access_token']
|
37
37
|
|
38
|
-
token_hash['got_token_at'] = Time.now.to_i
|
38
|
+
token_hash['got_token_at'] = Time.zone.now.to_i
|
39
39
|
token_hash['token_expires_in'] = token_hash.delete('expires_in')
|
40
40
|
write_token(token_hash)
|
41
41
|
end
|
@@ -63,7 +63,7 @@ module Wechat
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def remain_life_seconds
|
66
|
-
token_life_in_seconds - (Time.now.to_i - got_token_at)
|
66
|
+
token_life_in_seconds - (Time.zone.now.to_i - got_token_at)
|
67
67
|
end
|
68
68
|
|
69
69
|
private
|
@@ -77,7 +77,7 @@ module Wechat
|
|
77
77
|
|
78
78
|
record.access_token = token_hash['access_token']
|
79
79
|
record.token_expires_in = token_hash['token_expires_in']
|
80
|
-
record.got_token_at = Time.now
|
80
|
+
record.got_token_at = Time.zone.now
|
81
81
|
record.save || record.save(validate: false)
|
82
82
|
end
|
83
83
|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wechat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Skinnyworm
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
200/Tqe769E/Y40VHi+y7u06vT756gzVfC7nH5EUd2eIFAePlp8wMvNFW5+56bKl
|
36
36
|
LbbJnkHtUxxHWQTe2lJQuFErTSuYIaN9DhzJYNot7Ot7SPbdeChVsbPtjPg=
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date:
|
38
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: activesupport
|
@@ -58,25 +58,19 @@ dependencies:
|
|
58
58
|
- !ruby/object:Gem::Version
|
59
59
|
version: '9'
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
|
-
name:
|
61
|
+
name: httpx
|
62
62
|
requirement: !ruby/object:Gem::Requirement
|
63
63
|
requirements:
|
64
64
|
- - ">="
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: 1.
|
67
|
-
- - "<"
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '6'
|
66
|
+
version: 1.3.4
|
70
67
|
type: :runtime
|
71
68
|
prerelease: false
|
72
69
|
version_requirements: !ruby/object:Gem::Requirement
|
73
70
|
requirements:
|
74
71
|
- - ">="
|
75
72
|
- !ruby/object:Gem::Version
|
76
|
-
version: 1.
|
77
|
-
- - "<"
|
78
|
-
- !ruby/object:Gem::Version
|
79
|
-
version: '6'
|
73
|
+
version: 1.3.4
|
80
74
|
- !ruby/object:Gem::Dependency
|
81
75
|
name: nokogiri
|
82
76
|
requirement: !ruby/object:Gem::Requirement
|
@@ -153,28 +147,28 @@ dependencies:
|
|
153
147
|
requirements:
|
154
148
|
- - "~>"
|
155
149
|
- !ruby/object:Gem::Version
|
156
|
-
version: 1.
|
150
|
+
version: 1.72.2
|
157
151
|
type: :development
|
158
152
|
prerelease: false
|
159
153
|
version_requirements: !ruby/object:Gem::Requirement
|
160
154
|
requirements:
|
161
155
|
- - "~>"
|
162
156
|
- !ruby/object:Gem::Version
|
163
|
-
version: 1.
|
157
|
+
version: 1.72.2
|
164
158
|
- !ruby/object:Gem::Dependency
|
165
159
|
name: rails
|
166
160
|
requirement: !ruby/object:Gem::Requirement
|
167
161
|
requirements:
|
168
162
|
- - ">="
|
169
163
|
- !ruby/object:Gem::Version
|
170
|
-
version:
|
164
|
+
version: '7.2'
|
171
165
|
type: :development
|
172
166
|
prerelease: false
|
173
167
|
version_requirements: !ruby/object:Gem::Requirement
|
174
168
|
requirements:
|
175
169
|
- - ">="
|
176
170
|
- !ruby/object:Gem::Version
|
177
|
-
version:
|
171
|
+
version: '7.2'
|
178
172
|
- !ruby/object:Gem::Dependency
|
179
173
|
name: rspec-rails
|
180
174
|
requirement: !ruby/object:Gem::Requirement
|
@@ -248,6 +242,7 @@ files:
|
|
248
242
|
- lib/wechat.rb
|
249
243
|
- lib/wechat/api.rb
|
250
244
|
- lib/wechat/api_base.rb
|
245
|
+
- lib/wechat/api_config.rb
|
251
246
|
- lib/wechat/api_loader.rb
|
252
247
|
- lib/wechat/cipher.rb
|
253
248
|
- lib/wechat/concern/common.rb
|
@@ -276,9 +271,12 @@ licenses:
|
|
276
271
|
metadata:
|
277
272
|
bug_tracker_uri: https://github.com/Eric-Guo/wechat/issues
|
278
273
|
changelog_uri: https://github.com/Eric-Guo/wechat/releases
|
279
|
-
documentation_uri: https://github.com/Eric-Guo/wechat/tree/
|
280
|
-
source_code_uri: https://github.com/Eric-Guo/wechat/tree/
|
274
|
+
documentation_uri: https://github.com/Eric-Guo/wechat/tree/v1.0.1#readme
|
275
|
+
source_code_uri: https://github.com/Eric-Guo/wechat/tree/v1.0.1
|
281
276
|
rubygems_mfa_required: 'true'
|
277
|
+
post_install_message: |2
|
278
|
+
|
279
|
+
BREAKING changes: WECHAT_PROXY_URL should be written with port now, like `export WECHAT_PROXY_URL=http://127.0.0.1:6152`, since WECHAT_PROXY_PORT removed.
|
282
280
|
rdoc_options: []
|
283
281
|
require_paths:
|
284
282
|
- lib
|
@@ -293,7 +291,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
293
291
|
- !ruby/object:Gem::Version
|
294
292
|
version: 3.1.6
|
295
293
|
requirements: []
|
296
|
-
rubygems_version: 3.6.
|
294
|
+
rubygems_version: 3.6.9
|
297
295
|
specification_version: 4
|
298
296
|
summary: DSL for wechat message handling and API
|
299
297
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|