utils-rails 1.2.13
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +34 -0
- data/lib/utils/common.rb +19 -0
- data/lib/utils/file_util.rb +213 -0
- data/lib/utils/railtie.rb +8 -0
- data/lib/utils/sms.rb +58 -0
- data/lib/utils/view_helper.rb +66 -0
- data/lib/utils/weixin.rb +260 -0
- data/lib/utils/weixin_helper.rb +56 -0
- data/lib/utils/wxpay.rb +120 -0
- data/lib/utils.rb +61 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9b338086b803512c2d6ecadb85d0e420758ffc4368b08927c680a38ed6ef389f
|
4
|
+
data.tar.gz: 307553cbeeca15b2561a7d5dcf7d716064fe95091c80c546bc5437c04628522a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5b940d4e5403145aec99c05fff67636dfd09dc3b0d35fbc8ecf5965cdf121e6ed98768412b388ee49ff1d18e8e21dd219646d697a49b508ddb61d2f933051f05
|
7
|
+
data.tar.gz: 3b8ab3c1268d7a3515d64aa0ec34443153241e0daaac22acaa7fbc6d3dfc453b775310f7c4829f8eebbfc3965e14ae644c6f66a277b4dc409a2efd72f1383b21
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 Wangfuhai
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Utils'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
task default: :test
|
data/lib/utils/common.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Utils
|
2
|
+
class Common
|
3
|
+
|
4
|
+
def self.convert_bool(val)
|
5
|
+
ret = val
|
6
|
+
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'sqlite'
|
7
|
+
ret = "'t'" if val.to_i > 0
|
8
|
+
ret = "'f'" if val.to_i <= 0
|
9
|
+
end
|
10
|
+
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'mysql'
|
11
|
+
ret = 1 if val == 't'
|
12
|
+
ret = 0 if val == 'f'
|
13
|
+
end
|
14
|
+
|
15
|
+
ret
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module Utils
|
2
|
+
|
3
|
+
class FileUtil
|
4
|
+
|
5
|
+
#定义logger
|
6
|
+
def self.logger
|
7
|
+
Rails.logger
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.get_full_path(path,file_name="")
|
11
|
+
if Rails.configuration.respond_to?('upload_root') && !Rails.configuration.upload_root.blank?
|
12
|
+
full_path = File.join(Rails.configuration.upload_root,path).to_s
|
13
|
+
else
|
14
|
+
full_path = Rails.root.join("public",path).to_s
|
15
|
+
end
|
16
|
+
full_path = File.join(full_path,file_name) unless file_name.blank?
|
17
|
+
full_path
|
18
|
+
end
|
19
|
+
|
20
|
+
#获取预览图文件名
|
21
|
+
def self.get_thumb_file(file_name,extname="")
|
22
|
+
extname = File.extname(file_name) if extname.blank?
|
23
|
+
extname = "." + extname if extname.index('.').nil?
|
24
|
+
file_name[0..file_name.index('.')-1] + "_thumb" + extname unless file_name.index('.').nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
#获取移动图片文件名
|
28
|
+
def self.get_mobile_file(file_name,extname="")
|
29
|
+
extname = File.extname(file_name) if extname.blank?
|
30
|
+
extname = "." + extname if extname.index('.').nil?
|
31
|
+
file_name[0..file_name.index('.')-1] + "_mobile" + extname unless file_name.index('.').nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
#删除文件
|
35
|
+
def self.delete_file(file_name)
|
36
|
+
unless file_name.blank?
|
37
|
+
full_name = get_full_path(file_name)
|
38
|
+
#logger.debug("delete file:"+full_name.to_s)
|
39
|
+
File.delete(full_name) if File.exist?(full_name)
|
40
|
+
|
41
|
+
thumb_name = get_thumb_file(file_name)
|
42
|
+
full_name = get_full_path(thumb_name) if thumb_name
|
43
|
+
File.delete(full_name) if File.file?(full_name)
|
44
|
+
|
45
|
+
thumb_name = get_thumb_file(file_name,'jpg')
|
46
|
+
full_name = get_full_path(thumb_name) if thumb_name
|
47
|
+
File.delete(full_name) if File.file?(full_name)
|
48
|
+
|
49
|
+
mobile_name = get_mobile_file(file_name)
|
50
|
+
full_name = get_full_path(mobile_name) if mobile_name
|
51
|
+
File.delete(full_name) if File.file?(full_name)
|
52
|
+
|
53
|
+
mobile_name = get_mobile_file(file_name,'jpg')
|
54
|
+
full_name = get_full_path(mobile_name) if mobile_name
|
55
|
+
File.delete(full_name) if File.file?(full_name)
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
#检查文件上传许可
|
62
|
+
def self.check_ext(res_file)
|
63
|
+
if res_file
|
64
|
+
extname = File.extname(res_file.original_filename)
|
65
|
+
|
66
|
+
is_allowed_ext = false
|
67
|
+
Rails.configuration.upload_extname.split(';').each do |ext|
|
68
|
+
if ext.to_s.upcase == extname.to_s.upcase
|
69
|
+
is_allowed_ext = true
|
70
|
+
break
|
71
|
+
end
|
72
|
+
end
|
73
|
+
#logger.debug("res_file: "+ is_allowed_ext.to_s)
|
74
|
+
is_allowed_ext
|
75
|
+
else
|
76
|
+
true #无文件返回true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#上传文件
|
81
|
+
def self.upload (res_file,to_jpg=true,width=0) # res_file为 ActionController::UploadedFile 对象
|
82
|
+
if res_file
|
83
|
+
upload_path = get_upload_save_path
|
84
|
+
file_name = get_upload_save_name(res_file.original_filename,to_jpg)
|
85
|
+
|
86
|
+
abs_file_name = get_full_path(upload_path,file_name)
|
87
|
+
logger.debug("res_file:" + res_file.original_filename + ",abs_file_name:" + abs_file_name)
|
88
|
+
|
89
|
+
max_width = 0
|
90
|
+
max_width = Rails.configuration.image_max_width.to_i if Rails.configuration.respond_to?('image_max_width')
|
91
|
+
max_width = width unless width == 0
|
92
|
+
#只配置了image_max_width,才做图片缩小处理,jpg图质量统一使用80
|
93
|
+
if image_file?(abs_file_name) && (to_jpg || max_width > 0)
|
94
|
+
resize_image_file(res_file.path,abs_file_name,max_width)
|
95
|
+
else
|
96
|
+
File.open(abs_file_name, 'wb') do |file|
|
97
|
+
file.write(res_file.read)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
upload_path + "/" + file_name
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
#从URL保存文件
|
106
|
+
def self.save_from_url (url,to_jpg=false)
|
107
|
+
save_path = get_upload_save_path + "/" + get_upload_save_name(url,to_jpg)
|
108
|
+
save_path += ".jpg" if to_jpg && File.extname(save_path).blank?
|
109
|
+
conn = Faraday.new(:url => url)
|
110
|
+
File.open(get_full_path(save_path).to_s, 'wb') { |f| f.write(conn.get.body) }
|
111
|
+
return save_path
|
112
|
+
end
|
113
|
+
|
114
|
+
#获取上传文件保存路径
|
115
|
+
def self.get_upload_save_path
|
116
|
+
upload_path = "upload"
|
117
|
+
if Rails.configuration.respond_to?('upload_path') && !Rails.configuration.upload_path.blank?
|
118
|
+
upload_path = Rails.configuration.upload_path
|
119
|
+
end
|
120
|
+
upload_path += "/"+ Time.now.strftime("%Y%m/%d")
|
121
|
+
unless Dir.exist?(get_full_path(upload_path))
|
122
|
+
FileUtils.mkdir_p(get_full_path(upload_path))
|
123
|
+
end
|
124
|
+
upload_path
|
125
|
+
end
|
126
|
+
|
127
|
+
#获取上传文件保存名称
|
128
|
+
def self.get_upload_save_name(ori_filename,to_jpg=true)
|
129
|
+
file_name_main = (Time.now.to_f * 1000000).to_i.to_s(16) + Digest::SHA2.hexdigest(rand.to_s)[0,8]
|
130
|
+
file_name_ext = File.extname(ori_filename).downcase #扩展名统一小写
|
131
|
+
file_name_ext = ".jpg" if image_file?(ori_filename) && to_jpg
|
132
|
+
file_name = file_name_main + file_name_ext
|
133
|
+
end
|
134
|
+
|
135
|
+
#缩小图片尺寸
|
136
|
+
def self.resize_image_file(src_file,dst_file="",max_width=0)
|
137
|
+
return unless File.exist?(src_file)
|
138
|
+
image = MiniMagick::Image.open(src_file)
|
139
|
+
dst_file = src_file if dst_file.blank?
|
140
|
+
if image[:width] > max_width && max_width > 0
|
141
|
+
image.resize max_width.to_s + "x"
|
142
|
+
end
|
143
|
+
if File.extname(dst_file) == '.jpg'
|
144
|
+
image.format "jpg"
|
145
|
+
image.quality "80"
|
146
|
+
end
|
147
|
+
image.auto_orient
|
148
|
+
image.write dst_file
|
149
|
+
File.chmod(0644,dst_file) # MiniMagick没有处理图片(resize或format)而直接写文件时,默认把文件权限设为600
|
150
|
+
end
|
151
|
+
|
152
|
+
#检查是否图片文件名
|
153
|
+
def self.image_file?(file_name)
|
154
|
+
return !file_name.blank? && !!file_name.downcase.match("\\.png|\\.bmp|\\.jpeg|\\.jpg|\\.gif")
|
155
|
+
end
|
156
|
+
|
157
|
+
#生成缩略图
|
158
|
+
def self.thumb_image(file_name,format="jpg",size="0")
|
159
|
+
thumb_size = "300x"
|
160
|
+
thumb_size = Rails.configuration.image_thumb_size if Rails.configuration.respond_to?('image_thumb_size')
|
161
|
+
thumb_size = size.to_s unless size == "0"
|
162
|
+
|
163
|
+
resize_image(file_name,get_thumb_file(file_name),thumb_size)
|
164
|
+
resize_image(file_name,get_thumb_file(file_name,format),thumb_size) if File.extname(file_name).downcase.sub(".","") != format
|
165
|
+
end
|
166
|
+
|
167
|
+
#生成手机图
|
168
|
+
def self.mobile_image(file_name,format="jpg",size="0")
|
169
|
+
mobile_size = "720x"
|
170
|
+
mobile_size = Rails.configuration.image_thumb_size if Rails.configuration.respond_to?('image_mobile_size')
|
171
|
+
mobile_size = size.to_s unless size == "0"
|
172
|
+
|
173
|
+
resize_image(file_name,get_mobile_file(file_name),thumb_size)
|
174
|
+
resize_image(file_name,get_mobile_file(file_name,format),thumb_size) if File.extname(file_name).downcase.sub(".","") != format
|
175
|
+
end
|
176
|
+
|
177
|
+
#内部方法,不对外
|
178
|
+
def self.resize_image(src_file,dst_file,size)
|
179
|
+
#logger.debug(src_file + "," + dst_file + "," + size)
|
180
|
+
src_file = get_full_path(src_file) if !src_file.start_with?("/")
|
181
|
+
dst_file = get_full_path(dst_file) if !dst_file.start_with?("/")
|
182
|
+
if image_file?(src_file) && File.exist?(src_file)
|
183
|
+
image = MiniMagick::Image.open(src_file)
|
184
|
+
size += "x" if !!(size =~ /\A[0-9]+\z/) # 如果只设置一个数字,则默认为宽
|
185
|
+
size += ">" if size.index(">").nil? && size.index("<").nil? && size.index("^").nil? && size.index("!").nil? # 默认不放大,只缩小
|
186
|
+
#logger.debug(src_file + "," + dst_file + "," + size)
|
187
|
+
image.resize size
|
188
|
+
image.auto_orient
|
189
|
+
src_ext = File.extname(src_file).downcase.sub(".","")
|
190
|
+
dst_ext = File.extname(dst_file).downcase.sub(".","")
|
191
|
+
if src_ext != dst_ext
|
192
|
+
image.format dst_ext
|
193
|
+
image.quality "80" if dst_ext == 'jpg'
|
194
|
+
end
|
195
|
+
|
196
|
+
#image.combine_options do |i|
|
197
|
+
# i.resize "150x150^"
|
198
|
+
# i.gravity "center"
|
199
|
+
# i.crop "150x150+0+0"
|
200
|
+
# end
|
201
|
+
image.write dst_file
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
#获取图片文件信息
|
206
|
+
def self.get_image_info(file_name)
|
207
|
+
file_name = get_full_path(file_name) if !file_name.start_with?("/")
|
208
|
+
image = MiniMagick::Image.open(file_name)
|
209
|
+
return image
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
data/lib/utils/sms.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Utils
|
2
|
+
|
3
|
+
class Sms
|
4
|
+
|
5
|
+
#定义logger
|
6
|
+
def self.logger
|
7
|
+
Rails.logger
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.send(mobile,message,provider='')
|
11
|
+
provider = Rails.configuration.sms_provider if provider.blank? && Rails.configuration.respond_to?('sms_provider')
|
12
|
+
result = false
|
13
|
+
case provider
|
14
|
+
when 'yunpian'
|
15
|
+
result = send_by_yunpian(mobile,message)
|
16
|
+
end
|
17
|
+
result
|
18
|
+
end
|
19
|
+
def self.send_by_yunpian(mobile,message)
|
20
|
+
result = false
|
21
|
+
apikey = Rails.configuration.sms_apikey if Rails.configuration.respond_to?('sms_apikey')
|
22
|
+
uri = URI.parse("http://yunpian.com/v1/sms/send.json")
|
23
|
+
response = Net::HTTP.post_form(uri, {"apikey" => apikey,"mobile"=>mobile,"text"=>message})
|
24
|
+
ret = JSON.parse(response.body)
|
25
|
+
if ret["code"] == 0
|
26
|
+
result = true
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.send_verify_code(mobile,code,provider='')
|
32
|
+
provider = Rails.configuration.sms_provider if provider.blank? && Rails.configuration.respond_to?('sms_provider')
|
33
|
+
result = false
|
34
|
+
case provider
|
35
|
+
when 'yunpian'
|
36
|
+
result = send_verify_code_by_yunpian(mobile,code)
|
37
|
+
end
|
38
|
+
result
|
39
|
+
end
|
40
|
+
def self.send_verify_code_by_yunpian(mobile,code)
|
41
|
+
result = false
|
42
|
+
apikey = Rails.configuration.sms_apikey if Rails.configuration.respond_to?('sms_apikey')
|
43
|
+
company = Rails.configuration.sms_company if Rails.configuration.respond_to?('sms_company')
|
44
|
+
tpl_id = 1
|
45
|
+
tpl_id = Rails.configuration.sms_tpl_id if Rails.configuration.respond_to?('tpl_id')
|
46
|
+
tpl_value = "#code#=#{code}&#company#=#{company}"
|
47
|
+
uri = URI.parse("http://yunpian.com/v1/sms/tpl_send.json")
|
48
|
+
response = Net::HTTP.post_form(uri, {"apikey" => apikey,"mobile"=>mobile,
|
49
|
+
"tpl_id"=>tpl_id,"tpl_value"=>tpl_value})
|
50
|
+
ret = JSON.parse(response.body)
|
51
|
+
logger.debug("send_verify_code_by_yunpian:" + ret.to_s)
|
52
|
+
if ret["code"] == 0
|
53
|
+
result = true
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Utils
|
2
|
+
module ViewHelper
|
3
|
+
|
4
|
+
#输出布尔值标签
|
5
|
+
def bool_label(val)
|
6
|
+
output = "<span class=\"label " + (val ? 'label-success' : 'label-default') +
|
7
|
+
"\">" + (val ? '是' : '否') +"</span>"
|
8
|
+
output.html_safe
|
9
|
+
end
|
10
|
+
|
11
|
+
#输出预览图
|
12
|
+
def thumbnail(file,width=150,use_thumb=true)
|
13
|
+
output = '暂无图片'
|
14
|
+
unless file.blank?
|
15
|
+
if use_thumb
|
16
|
+
thumb_file = Utils::FileUtil.get_thumb_file(file)
|
17
|
+
full_name = Rails.root.join("public",thumb_file.to_s)
|
18
|
+
file = thumb_file if File.file?(full_name)
|
19
|
+
end
|
20
|
+
file = "/" + file if !file.start_with?("/") && !file.start_with?("http://")
|
21
|
+
output = "<div class=\"img-thumbnail\">" + image_tag(file,:width=>width) +"</div>"
|
22
|
+
end
|
23
|
+
|
24
|
+
output.html_safe
|
25
|
+
end
|
26
|
+
|
27
|
+
#字符串截取
|
28
|
+
def str_trim(str,length,postfix='...')
|
29
|
+
str[0,length]+(str.length > length ? postfix : "") if str
|
30
|
+
end
|
31
|
+
|
32
|
+
#分页显示标签
|
33
|
+
def info_paginate(collection, options = {})
|
34
|
+
pre_page = collection.current_page - 1
|
35
|
+
next_page = collection.current_page + 1
|
36
|
+
html = ""
|
37
|
+
html += "<div id=\"" + options[:container] = "\">" unless options[:container].nil?
|
38
|
+
|
39
|
+
html += "<span>共<span>" + collection.total_entries.to_s + "</span>条记录<span>" +
|
40
|
+
collection.total_pages.to_s + "</span>页</span>" if options[:show_total]
|
41
|
+
|
42
|
+
html += "<span><a id=\"first\" href=\"" + url_for(params.merge(:page=> "1")) +
|
43
|
+
"\">第一页</a></span>" if options[:full_link] && collection.current_page > 1
|
44
|
+
|
45
|
+
if pre_page > 0
|
46
|
+
html += "<span><a id=\"prev\" href=\"" + url_for(params.merge(:page=> pre_page)) + "\""
|
47
|
+
html += " class=\"" + options[:class] + "\"" unless options[:class].nil?
|
48
|
+
html += ">上一页</a></span>"
|
49
|
+
end
|
50
|
+
|
51
|
+
html += "<span>当前第<span>" + collection.current_page.to_s + "</span>页</span>" if options[:full_link]
|
52
|
+
|
53
|
+
if next_page <= collection.total_pages
|
54
|
+
html += "<span><a id=\"next\" href=\"" + url_for(params.merge(:page=> next_page)) + "\""
|
55
|
+
html += " class=\"" + options[:class] + "\"" unless options[:class].nil?
|
56
|
+
html += ">下一页</a></span>"
|
57
|
+
end
|
58
|
+
|
59
|
+
html += "<span><a id=\"last\" href=\"" + url_for(params.merge(:page=> collection.total_pages)) +
|
60
|
+
"\">最后一页</a></span>" if options[:full_link] && collection.current_page < collection.total_pages
|
61
|
+
html += "</div>" unless options[:container].nil?
|
62
|
+
html.html_safe
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/lib/utils/weixin.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
module Utils
|
2
|
+
class Weixin
|
3
|
+
@@ticket_list = {}
|
4
|
+
@@access_token_list = {}
|
5
|
+
@@oauth2_access_token_list = {}
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :app_id,:app_secret,:mch_id,:pay_sign_key,:oauth2_state
|
9
|
+
end
|
10
|
+
|
11
|
+
#定义logger
|
12
|
+
def self.logger
|
13
|
+
Rails.logger
|
14
|
+
end
|
15
|
+
|
16
|
+
#提交数据
|
17
|
+
def self.post_data(data,path)
|
18
|
+
logger.debug("data:"+ JSON.parse(data).to_s)
|
19
|
+
uri = URI.parse("https://api.weixin.qq.com/")
|
20
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
21
|
+
http.use_ssl = true
|
22
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
23
|
+
request = Net::HTTP::Post.new(path)
|
24
|
+
request.add_field('Content-Type', 'application/json')
|
25
|
+
request.body = data
|
26
|
+
response = http.request(request)
|
27
|
+
|
28
|
+
result = JSON.parse(response.body)
|
29
|
+
logger.debug("result:"+result.to_s)
|
30
|
+
return result
|
31
|
+
end
|
32
|
+
|
33
|
+
#获取oauth2 url
|
34
|
+
def self.get_oauth2_url(redirect_uri,auth_type="snsapi_userinfo",app_id=nil)
|
35
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
36
|
+
redirect_uri = CGI::escape(redirect_uri)
|
37
|
+
|
38
|
+
state = 'oauth2'
|
39
|
+
state = Utils::Weixin.oauth2_state if Utils::Weixin.respond_to?('oauth2_state')
|
40
|
+
url = "https://open.weixin.qq.com/connect/oauth2/authorize?" +
|
41
|
+
"appid=" + app_id + "&redirect_uri=" + redirect_uri + "&response_type=code" +
|
42
|
+
"&scope=" + auth_type + "&state=" + state + "#wechat_redirect"
|
43
|
+
return url
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.get_oauth2_access_token(code,app_id=nil,app_secret=nil)
|
47
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
48
|
+
app_secret = Utils::Weixin.app_secret if app_secret.nil?
|
49
|
+
cache = @@oauth2_access_token_list[app_id]
|
50
|
+
|
51
|
+
token = nil
|
52
|
+
logger.debug("Utils::Weixin.get_access_token,cache access_token:"+cache.to_s)
|
53
|
+
if cache.nil? || cache[:expire_time].nil? ||
|
54
|
+
cache[:expire_time] - 600 < Time.now.to_i
|
55
|
+
#提前十分钟过期,避免时间不同步导致时间差异
|
56
|
+
|
57
|
+
return if code.blank? # 首次调用code为空时直接返回
|
58
|
+
|
59
|
+
url = "https://api.weixin.qq.com/sns/oauth2/access_token"
|
60
|
+
url += "?appid=" + app_id
|
61
|
+
url += "&secret=" + app_secret
|
62
|
+
url += "&code=" + code
|
63
|
+
url += "&grant_type=authorization_code"
|
64
|
+
|
65
|
+
conn = Faraday.new(:url => url,headers: { accept_encoding: 'none' })
|
66
|
+
result = JSON.parse conn.get.body
|
67
|
+
logger.debug("get oauth2_access_token result :"+result.to_s)
|
68
|
+
if result['access_token']
|
69
|
+
cache = {} if cache.nil?
|
70
|
+
cache[:access_token] = result['access_token']
|
71
|
+
cache[:expire_time] = Time.now.to_i + result['expires_in'].to_i
|
72
|
+
token = cache[:access_token]
|
73
|
+
@@oauth2_access_token_list[app_id] = cache # 更新缓存
|
74
|
+
logger.debug("Utils::Weixin.get_oauth2_access_token,access_token is update:"+cache[:access_token])
|
75
|
+
else
|
76
|
+
logger.error('Utils::Weixin.get_oauth2_access_token,获取access_token出错:' + result['errmsg'].to_s)
|
77
|
+
end
|
78
|
+
else
|
79
|
+
token = cache[:access_token]
|
80
|
+
end
|
81
|
+
return token
|
82
|
+
end
|
83
|
+
|
84
|
+
#获取opendid,用于snsapi_base授权
|
85
|
+
def self.get_openid(code,app_id=nil,app_secret=nil)
|
86
|
+
openid,access_token = Utils::Weixin.get_openid_and_access_token(code,app_id,app_secret)
|
87
|
+
return openid
|
88
|
+
end
|
89
|
+
#同时获取openid和access_token,用于snsapi_userinfo授权
|
90
|
+
def self.get_openid_and_access_token(code,app_id=nil,app_secret=nil)
|
91
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
92
|
+
app_secret = Utils::Weixin.app_secret if app_secret.nil?
|
93
|
+
path = "/sns/oauth2/access_token?appid=" + app_id + "&secret=" + app_secret +
|
94
|
+
"&code=" + code + "&grant_type=authorization_code"
|
95
|
+
uri = URI.parse("https://api.weixin.qq.com/")
|
96
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
97
|
+
http.use_ssl = true
|
98
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
99
|
+
request = Net::HTTP::Get.new(path)
|
100
|
+
request.add_field('Content-Type', 'application/json')
|
101
|
+
response = http.request(request)
|
102
|
+
result = JSON.parse(response.body)
|
103
|
+
logger.error("Utils::Weixin.get_openid fail,result:"+result.to_s) if result["openid"].blank?
|
104
|
+
openid = access_token = nil
|
105
|
+
openid = result["openid"] if result["openid"]
|
106
|
+
access_token = result["access_token"] if result["access_token"]
|
107
|
+
return openid,access_token
|
108
|
+
end
|
109
|
+
|
110
|
+
#通过网页授权获取用户信息(无须关注公众号)
|
111
|
+
def self.get_userinfo_by_authcode(code,app_id=nil,app_secret=nil)
|
112
|
+
openid,access_token = get_openid_and_access_token(code,app_id,app_secret)
|
113
|
+
return get_userinfo_by_auth(access_token,openid)
|
114
|
+
end
|
115
|
+
def self.get_userinfo_by_auth(access_token,openid)
|
116
|
+
url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token.to_s +
|
117
|
+
"&openid=" + openid.to_s + "&lang=zh_CN"
|
118
|
+
conn = Faraday.new(:url => url)
|
119
|
+
result = JSON.parse conn.get.body
|
120
|
+
if result["errmsg"]
|
121
|
+
logger.error("Utils::Weixin.get_userinfo_by_auth of openid: "+ openid.to_s +
|
122
|
+
",access_token:" + access_token.to_s + ", error:" + result["errmsg"])
|
123
|
+
end
|
124
|
+
result
|
125
|
+
end
|
126
|
+
|
127
|
+
#获取用户信息(仅对关注者有效)
|
128
|
+
def self.get_userinfo(openid,app_id=nil,app_secret=nil)
|
129
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
130
|
+
app_secret = Utils::Weixin.app_secret if app_secret.nil?
|
131
|
+
access_token = get_access_token(app_id,app_secret)
|
132
|
+
url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + access_token +
|
133
|
+
"&openid=" + openid + "&lang=zh_CN"
|
134
|
+
conn = Faraday.new(:url => url)
|
135
|
+
result = JSON.parse conn.get.body
|
136
|
+
if result["errmsg"]
|
137
|
+
logger.error("Utils::Weixin.get_userinfo of "+ openid.to_s + " error:" + result["errmsg"])
|
138
|
+
end
|
139
|
+
result
|
140
|
+
end
|
141
|
+
|
142
|
+
#获取基础access_token
|
143
|
+
def self.get_access_token(app_id=nil,app_secret=nil)
|
144
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
145
|
+
app_secret = Utils::Weixin.app_secret if app_secret.nil?
|
146
|
+
cache = @@access_token_list[app_id]
|
147
|
+
|
148
|
+
token = nil
|
149
|
+
logger.debug("Utils::Weixin.get_access_token,cache access_token:"+cache.to_s)
|
150
|
+
if cache.nil? || cache[:expire_time].nil? ||
|
151
|
+
cache[:expire_time] - 600 < Time.now.to_i
|
152
|
+
#提前十分钟过期,避免时间不同步导致时间差异
|
153
|
+
|
154
|
+
url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+
|
155
|
+
app_id.to_s + "&secret=" + app_secret.to_s
|
156
|
+
result =JSON.parse(Net::HTTP.get(URI.parse(url)))
|
157
|
+
logger.debug("get access_token result :"+result.to_s)
|
158
|
+
if result['access_token']
|
159
|
+
cache = {} if cache.nil?
|
160
|
+
cache[:access_token] = result['access_token']
|
161
|
+
cache[:expire_time] = Time.now.to_i + result['expires_in'].to_i
|
162
|
+
token = cache[:access_token]
|
163
|
+
@@access_token_list[app_id] = cache # 更新缓存
|
164
|
+
logger.debug("Utils::Weixin.get_access_token,access_token is update:"+cache[:access_token])
|
165
|
+
else
|
166
|
+
logger.error('Utils::Weixin.get_access_token,获取access_token出错:' + result['errmsg'].to_s)
|
167
|
+
end
|
168
|
+
else
|
169
|
+
token = cache[:access_token]
|
170
|
+
end
|
171
|
+
return token
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.get_ticket(type="jsapi",access_token="",app_id=nil,app_secret=nil)
|
175
|
+
access_token = get_access_token(app_id,app_secret) if access_token.blank?
|
176
|
+
key = access_token.to_s + "_" + type
|
177
|
+
cache = @@ticket_list[key]
|
178
|
+
ticket = nil
|
179
|
+
logger.debug("Utils::Weixin.get_ticket,cache ticket:"+cache.to_s)
|
180
|
+
if cache.nil? || cache[:expire_time].nil? ||
|
181
|
+
cache[:expire_time] - 600 < Time.now.to_i
|
182
|
+
#提前十分钟过期,避免时间不同步导致时间差异
|
183
|
+
url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token.to_s +
|
184
|
+
"&type=" + type.to_s
|
185
|
+
result =JSON.parse(Net::HTTP.get(URI.parse(url)))
|
186
|
+
logger.debug("get get_ticket result :"+result.to_s)
|
187
|
+
if result['ticket']
|
188
|
+
cache = {} if cache.nil?
|
189
|
+
cache[:ticket] = result['ticket']
|
190
|
+
cache[:expire_time] = Time.now.to_i + result['expires_in'].to_i
|
191
|
+
ticket = cache[:ticket]
|
192
|
+
@@ticket_list[key] = cache # 更新缓存
|
193
|
+
logger.debug("Utils::Weixin.get_ticket,ticket is update:" + cache[:ticket].to_s)
|
194
|
+
else
|
195
|
+
logger.error('Utils::Weixin.get_ticket,获取ticket出错:' + result['errmsg'].to_s)
|
196
|
+
end
|
197
|
+
else
|
198
|
+
ticket = cache[:ticket]
|
199
|
+
end
|
200
|
+
return ticket
|
201
|
+
end
|
202
|
+
|
203
|
+
#发送客服消息
|
204
|
+
def self.send_customer_message(to_openid,message,app_id=nil,app_secret=nil)
|
205
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
206
|
+
app_secret = Utils::Weixin.app_secret if app_secret.nil?
|
207
|
+
access_token = get_access_token(app_id,app_secret)
|
208
|
+
data = '{"touser":"'+ to_openid +'" , "msgtype": "text", "text": {"content": "' +
|
209
|
+
message + '"}}'
|
210
|
+
path = '/cgi-bin/message/custom/send?access_token=' + access_token
|
211
|
+
result = post_data(data,path)
|
212
|
+
if result["errcode"] != 0
|
213
|
+
logger.error("Utils::Weixin.send_customer_message to :"+to_openid + " result:" + result["errmsg"])
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
#发送模板消息
|
218
|
+
def self.send_template_message(to_openid,template_id,message,url='',top_color='#FF0000',value_color='#173177',
|
219
|
+
app_id=nil,app_secret=nil)
|
220
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
221
|
+
app_secret = Utils::Weixin.app_secret if app_secret.nil?
|
222
|
+
access_token = get_access_token(app_id,app_secret)
|
223
|
+
|
224
|
+
data = '{"touser":"'+ to_openid +'","template_id":"' + template_id +'","url":"' + url + '",' +
|
225
|
+
'"topcolor":"' + top_color + '","data":{'
|
226
|
+
message.each do |m_k,m_v|
|
227
|
+
data += '"' + m_k + '":{"value":"' + m_v + '","color":"' + value_color + '"},'
|
228
|
+
end
|
229
|
+
data.chop! if data.end_with?(',')
|
230
|
+
data += '}}'
|
231
|
+
logger.debug("send_template_message data:" + data)
|
232
|
+
path = '/cgi-bin/message/template/send?access_token=' + access_token
|
233
|
+
result = post_data(data,path)
|
234
|
+
if result["errcode"] != 0
|
235
|
+
logger.error("Utils::Weixin.send_template_message to :"+to_openid + " result:" + result["errmsg"])
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
#sign_string :appid, :appkey, :noncestr, :package, :timestamp
|
241
|
+
def self.api_sign(sign_params = {},sign_type = 'SHA1')
|
242
|
+
#logger.debug(sign_params)
|
243
|
+
result_string = ''
|
244
|
+
sign_params = sign_params.sort
|
245
|
+
sign_params.each{|key,value|
|
246
|
+
result_string += (key.to_s + '=' + value.to_s + '&')
|
247
|
+
}
|
248
|
+
result_string = result_string[0, result_string.length - 1]#去掉多余的&号
|
249
|
+
logger.debug(result_string)
|
250
|
+
sign = Digest::MD5.hexdigest(result_string).upcase if sign_type == 'MD5'
|
251
|
+
sign = Digest::SHA1.hexdigest(result_string) if sign_type == 'SHA1'
|
252
|
+
sign
|
253
|
+
end
|
254
|
+
#兼容老接口
|
255
|
+
def self.pay_sign(sign_params = {},sign_type = 'SHA1')
|
256
|
+
api_sign(sign_params,sign_type)
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Utils
|
2
|
+
module WeixinHelper
|
3
|
+
|
4
|
+
#调用微信接口获取openid,并设置在session中,如果指定scope为snsapi_userinfo,将返回access_token
|
5
|
+
def set_session_openid(session_name='openid',app_id=nil,app_secret=nil,scope='snsapi_base')
|
6
|
+
#测试 start o6hyyjlRoyQelo6YgWstsRJjSBb8
|
7
|
+
unless params[:openid].blank?
|
8
|
+
#TODO 校验是从微信传过来的参数才写入session;或者使用加密参数,用于没有网页授权接口权限的公众号
|
9
|
+
#开发模式下才采用
|
10
|
+
session[session_name] = params[:openid] if Rails.env == 'development'
|
11
|
+
end
|
12
|
+
#logger.debug("session[:openid]:" + session[:openid] )
|
13
|
+
#测试 end
|
14
|
+
|
15
|
+
#已设置openid且不用获取用户信息,直接返回
|
16
|
+
return if !session[session_name].blank? && scope == 'snsapi_base'
|
17
|
+
|
18
|
+
state = 'oauth2'
|
19
|
+
state = Utils::Weixin.oauth2_state if Utils::Weixin.respond_to?('oauth2_state')
|
20
|
+
if !params[:state].nil? && params[:state] == state && params[:code] #从授权接口返回
|
21
|
+
openid = Utils::Weixin.get_openid(params[:code],app_id,app_secret) if scope == 'snsapi_base'
|
22
|
+
openid,access_token = Utils::Weixin.get_openid_and_access_token(params[:code],app_id,
|
23
|
+
app_secret) if scope == 'snsapi_userinfo'
|
24
|
+
if openid
|
25
|
+
session[session_name] = openid
|
26
|
+
return access_token if scope == 'snsapi_userinfo'
|
27
|
+
else
|
28
|
+
render text: "获取微信用户标识openid失败"
|
29
|
+
end
|
30
|
+
else
|
31
|
+
render text: "微信接口返回参数错误(state,code)或用户未授权访问" if !params[:state].nil?
|
32
|
+
end
|
33
|
+
if params[:state].nil?
|
34
|
+
#如果有state参数,表示从接口返回,不需再跳转
|
35
|
+
redirect_to Utils::Weixin.get_oauth2_url(request.original_url,scope,app_id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#获取oauth2 access_token,并设置实例变量
|
40
|
+
def set_oauth2_access_token(app_id=nil,app_secret=nil)
|
41
|
+
state = 'oauth2'
|
42
|
+
state = Utils::Weixin.oauth2_state if Utils::Weixin.respond_to?('oauth2_state')
|
43
|
+
if !params[:state].nil? && params[:state] == state && params[:code] #从授权接口返回
|
44
|
+
@oauth2_access_token = Utils::Weixin.get_oauth2_access_token(params[:code],app_id,app_secret)
|
45
|
+
return
|
46
|
+
end
|
47
|
+
token = Utils::Weixin.get_oauth2_access_token("",app_id,app_secret)
|
48
|
+
if token.nil?
|
49
|
+
redirect_to Utils::Weixin.get_oauth2_url(request.original_url,'snsapi_base',app_id)
|
50
|
+
else
|
51
|
+
@oauth2_access_token = token
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/utils/wxpay.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'xmlsimple'
|
2
|
+
|
3
|
+
module Utils
|
4
|
+
class Wxpay
|
5
|
+
|
6
|
+
#定义logger
|
7
|
+
def self.logger
|
8
|
+
Rails.logger
|
9
|
+
end
|
10
|
+
|
11
|
+
#提交数据
|
12
|
+
def self.post_xml_data(data,path)
|
13
|
+
logger.debug("data:"+ data.to_s)
|
14
|
+
uri = URI.parse("https://api.mch.weixin.qq.com/")
|
15
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
16
|
+
http.use_ssl = true
|
17
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
18
|
+
request = Net::HTTP::Post.new(path)
|
19
|
+
request.add_field('Content-Type', 'application/json')
|
20
|
+
request.body = data
|
21
|
+
response = http.request(request)
|
22
|
+
logger.debug("body:"+ response.body)
|
23
|
+
result = XmlSimple.xml_in(response.body)
|
24
|
+
logger.debug("result:"+result.to_s)
|
25
|
+
return result
|
26
|
+
end
|
27
|
+
|
28
|
+
#微信支付处理(NATIVE)
|
29
|
+
def self.native(out_trade_no,total_fee,body,notify_url,openid,ip,return_code=true,app_id=nil,mch_id=nil,pay_sign_key=nil)
|
30
|
+
result = Utils::Wxpay.unifiedorder('NATIVE',out_trade_no,total_fee,body,notify_url,openid,ip,app_id,mch_id,pay_sign_key)
|
31
|
+
return nil if result.nil?
|
32
|
+
|
33
|
+
if return_code
|
34
|
+
return result["code_url"][0] #模式二返回结果
|
35
|
+
else
|
36
|
+
package_params = {
|
37
|
+
:appId => app_id,
|
38
|
+
:timeStamp => Time.now.to_i.to_s,#必须是字符串,否则iPhone下报错
|
39
|
+
:nonceStr => Digest::MD5.hexdigest(Time.now.to_s).to_s,
|
40
|
+
:package => "prepay_id=" + result["prepay_id"][0],
|
41
|
+
:signType => "MD5"
|
42
|
+
}
|
43
|
+
package_params[:paySign] = Utils::Wxpay.pay_sign(package_params,pay_sign_key)
|
44
|
+
return package_params #模式一返回结果
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#微信支付处理(JSAPI v2)
|
49
|
+
def self.jsapi2(out_trade_no,total_fee,body,notify_url,openid,ip,app_id=nil,mch_id=nil,pay_sign_key=nil)
|
50
|
+
return Utils::Wxpay.unifiedorder('JSAPI',out_trade_no,total_fee,body,notify_url,openid,ip,app_id,mch_id,pay_sign_key)
|
51
|
+
end
|
52
|
+
|
53
|
+
#微信支付统一调用接口
|
54
|
+
def self.unifiedorder(trade_type,out_trade_no,total_fee,body,notify_url,openid,ip,app_id,mch_id,pay_sign_key)
|
55
|
+
app_id = Utils::Weixin.app_id if app_id.nil?
|
56
|
+
pay_sign_key= Utils::Weixin.pay_sign_key if pay_sign_key.nil?
|
57
|
+
mch_id= Utils::Weixin.mch_id if mch_id.nil?
|
58
|
+
|
59
|
+
#构造支付订单接口参数
|
60
|
+
pay_params = {
|
61
|
+
:appid => app_id,
|
62
|
+
:mch_id => mch_id,
|
63
|
+
:body => body,
|
64
|
+
:nonce_str => Digest::MD5.hexdigest(Time.now.to_s).to_s,
|
65
|
+
:notify_url => notify_url, #'http://szework.com/weixin/pay/notify',#get_notify_url(),
|
66
|
+
:out_trade_no => out_trade_no, #out_trade_no, #'2014041311110001'
|
67
|
+
:total_fee => total_fee,
|
68
|
+
:trade_type => trade_type,
|
69
|
+
:openid => openid,
|
70
|
+
:spbill_create_ip => ip #TODO 支持反向代理
|
71
|
+
}
|
72
|
+
|
73
|
+
path = "/pay/unifiedorder"
|
74
|
+
data = "<xml>"
|
75
|
+
pay_params.each do |k,v|
|
76
|
+
data += "<" + k.to_s + "><![CDATA[" + v.to_s + "]]></" + k.to_s + ">"
|
77
|
+
end
|
78
|
+
data += "<sign><![CDATA[" + pay_sign(pay_params,pay_sign_key) + "]]></sign>"
|
79
|
+
data += "</xml>"
|
80
|
+
result = post_xml_data(data,path)
|
81
|
+
if result["return_code"][0] == 'SUCCESS' && result["result_code"][0] == 'SUCCESS'
|
82
|
+
#JSAPI调用返回
|
83
|
+
if result["trade_type"][0] == 'JSAPI'
|
84
|
+
package_params = {
|
85
|
+
:appId => app_id,
|
86
|
+
:timeStamp => Time.now.to_i.to_s,#必须是字符串,否则iPhone下报错
|
87
|
+
:nonceStr => Digest::MD5.hexdigest(Time.now.to_s).to_s,
|
88
|
+
:package => "prepay_id=" + result["prepay_id"][0],
|
89
|
+
:signType => "MD5"
|
90
|
+
}
|
91
|
+
package_params[:paySign] = Utils::Wxpay.pay_sign(package_params,pay_sign_key)
|
92
|
+
return package_params
|
93
|
+
end
|
94
|
+
|
95
|
+
#NATIVE调用返回
|
96
|
+
return result
|
97
|
+
else
|
98
|
+
#调用失败
|
99
|
+
logger.info("weixin_pay.error:" + result["return_msg"].to_s + ";" +
|
100
|
+
result["err_code_des"].to_s )
|
101
|
+
return nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
#sign_string :appid, :appkey, :noncestr, :package, :timestamp
|
107
|
+
def self.pay_sign(sign_params = {},key)
|
108
|
+
#logger.debug(sign_params)
|
109
|
+
result_string = ''
|
110
|
+
sign_params = sign_params.sort
|
111
|
+
sign_params.each{|key,value|
|
112
|
+
result_string += (key.to_s + '=' + value.to_s + '&') unless value.blank?
|
113
|
+
}
|
114
|
+
result_string +="key=" + key
|
115
|
+
sign = Digest::MD5.hexdigest(result_string).upcase
|
116
|
+
sign
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
data/lib/utils.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'utils/common'
|
2
|
+
require 'utils/file_util'
|
3
|
+
require 'utils/sms'
|
4
|
+
require 'utils/weixin'
|
5
|
+
require 'utils/weixin_helper'
|
6
|
+
require 'utils/wxpay'
|
7
|
+
require 'utils/railtie' if defined?(Rails)
|
8
|
+
|
9
|
+
module Utils
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class String
|
14
|
+
def to_bool
|
15
|
+
return true if self == true || self =~ (/^(true|t|yes|y|1)$/i)
|
16
|
+
return false if self == false || self.blank? || self =~ (/^(false|f|no|n|0)$/i)
|
17
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Fixnum
|
22
|
+
def to_bool
|
23
|
+
return true if self == 1
|
24
|
+
return false if self == 0
|
25
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class TrueClass
|
30
|
+
def to_i; 1; end
|
31
|
+
def to_bool; self; end
|
32
|
+
end
|
33
|
+
|
34
|
+
class FalseClass
|
35
|
+
def to_i; 0; end
|
36
|
+
def to_bool; self; end
|
37
|
+
end
|
38
|
+
|
39
|
+
class NilClass
|
40
|
+
def to_bool; false; end
|
41
|
+
end
|
42
|
+
|
43
|
+
module HTTPResponseDecodeContentOverride
|
44
|
+
def initialize(h,c,m)
|
45
|
+
super(h,c,m)
|
46
|
+
@decode_content = true
|
47
|
+
end
|
48
|
+
def body
|
49
|
+
res = super
|
50
|
+
if self['content-length']
|
51
|
+
self['content-length']= res.bytesize
|
52
|
+
end
|
53
|
+
res
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module Net
|
58
|
+
class HTTPResponse
|
59
|
+
prepend HTTPResponseDecodeContentOverride
|
60
|
+
end
|
61
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: utils-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.13
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- wangfuhai
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-12-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mini_magick
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: xml-simple
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: utils with rails
|
56
|
+
email:
|
57
|
+
- wangfuhai@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- MIT-LICENSE
|
63
|
+
- README.rdoc
|
64
|
+
- Rakefile
|
65
|
+
- lib/utils.rb
|
66
|
+
- lib/utils/common.rb
|
67
|
+
- lib/utils/file_util.rb
|
68
|
+
- lib/utils/railtie.rb
|
69
|
+
- lib/utils/sms.rb
|
70
|
+
- lib/utils/view_helper.rb
|
71
|
+
- lib/utils/weixin.rb
|
72
|
+
- lib/utils/weixin_helper.rb
|
73
|
+
- lib/utils/wxpay.rb
|
74
|
+
homepage: https://github.com/wangfuhai2013/utils-rails
|
75
|
+
licenses:
|
76
|
+
- MIT
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubygems_version: 3.3.7
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: utils with rails
|
97
|
+
test_files: []
|