simple_wx 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3352241216ce336988e4fa27a330ba1d723e0558
4
+ data.tar.gz: e07e3618c8533fdf0afae69d27b08ea7b554f6a5
5
+ SHA512:
6
+ metadata.gz: ca678fc595eef2f1424dd3b6b34c21d1577ff80c03b6e6300e22ddc5cb1798b97276fb7fd28c14c01d1853cac726164082233f1b0bdd78df712242e56c4575d2
7
+ data.tar.gz: cb8a81f1373d22ab77a7e5cbb38cfe9cb6a5d8a34218cccd6c3501486e653ac81c402d1beed8e8dd8cc04ca8c0a8c76461f07d17662f08c70dfae47dca026437
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ /.idea
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ ## initializers/simple_wx.rb:
2
+ ```
3
+ WeixinSetting = YAML.load_file(File.join "#{Rails.root}", "config", "weixin.yml")[Rails.env || "development"]
4
+
5
+ module SimpleWx
6
+ @@weixin_config = YAML.load_file(File.join "#{Rails.root}", "config", "weixin.yml")[Rails.env || "development"]
7
+ @@logger = Rails.logger
8
+ @@redis = Redis::Objects.redis
9
+ end
10
+ ```
11
+
12
+ ## config/weixin.yml:
13
+ ```
14
+ development:
15
+ app_id: app_id
16
+ app_secret: app_secret
17
+ serial_no: 微信号 (gh...)
18
+ token: token
19
+
20
+ production:
21
+ # ...
22
+ ```
@@ -0,0 +1,5 @@
1
+ module SimpleWx
2
+ @@weixin_config = YAML.load_file(File.join "#{Rails.root}", "config", "weixin.yml")[Rails.env || "development"]
3
+ @@logger = Rails.logger
4
+ @@redis = Redis::Objects.redis
5
+ end
@@ -0,0 +1,79 @@
1
+ module SimpleWx
2
+ class AccessToken < Base
3
+
4
+ ### Usage
5
+ #
6
+ # ---------- class-methods ----------
7
+ #
8
+ # SimpleWx::AccessToken.access_token
9
+ # SimpleWx::AccessToken.server_ip
10
+ # SimpleWx::AccessToken.jsapi_ticket
11
+ #
12
+ # ---------- instance-methods -----------
13
+ #
14
+ # at = SimpleWx::AccessToken.new
15
+ # at.access_token
16
+ # at.server_ip
17
+ # if at.error.present?
18
+ # ...
19
+ # end
20
+ #
21
+
22
+
23
+ def server_ip
24
+ url = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=#{access_token}"
25
+ response = RestClient.get url
26
+ response_json = errcode_check(JSON.parse(response))
27
+ @server_ip = response_json["ip_list"]
28
+ end
29
+
30
+ def access_token
31
+ SimpleWx.redis.exists("__weixin_access_token__") ? \
32
+ SimpleWx.redis.get("__weixin_access_token__") : get_new_token
33
+ end
34
+
35
+ def jsapi_ticket
36
+ SimpleWx.redis.exists("__jsapi_ticket__") ? \
37
+ SimpleWx.redis.get("__jsapi_ticket__") : get_new_jsapi_ticket
38
+ end
39
+
40
+ private
41
+
42
+ def get_new_jsapi_ticket
43
+ url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=#{access_token}&type=jsapi"
44
+ response = RestClient.get url
45
+ response_json = errcode_check(JSON.parse(response))
46
+ jsapi_ticket = response_json["ticket"]
47
+ if @error.blank?
48
+ SimpleWx.redis.multi do
49
+ SimpleWx.redis.set "__jsapi_ticket__", jsapi_ticket
50
+ SimpleWx.redis.expire "__jsapi_ticket__", 30.minutes.to_i
51
+ end
52
+ end
53
+ jsapi_ticket
54
+ end
55
+
56
+ def get_new_token
57
+ url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=#{SimpleWx.weixin_config["app_id"]}&secret=#{SimpleWx.weixin_config["app_secret"]}"
58
+ response = RestClient.get url
59
+ response_json = errcode_check(JSON.parse(response))
60
+ access_token = response_json["access_token"]
61
+ if @error.blank?
62
+ SimpleWx.redis.multi do
63
+ SimpleWx.redis.set "__weixin_access_token__", access_token
64
+ SimpleWx.redis.expire "__weixin_access_token__", 30.minutes.to_i
65
+ end
66
+ end
67
+ access_token
68
+ end
69
+
70
+ def self.method_missing m
71
+ instance = self.new
72
+ if instance.public_methods(false).include? m.to_sym
73
+ return instance.send(m)
74
+ else
75
+ super
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,37 @@
1
+ module SimpleWx
2
+ class Base
3
+ attr_accessor :error, :raise_flag
4
+
5
+ def initialize options = {}
6
+ raise 'SimpleWx.weixin_config is blank.' if SimpleWx.weixin_config.blank?
7
+ @raise_flag = options[:raise_flag]
8
+ @log_flag = options[:log_flag]
9
+ @error = {}
10
+ end
11
+
12
+ protected
13
+
14
+ def errcode_check json, log_flag = nil
15
+
16
+ # 每次执行刷新 @error
17
+ # 根据 log_flag 打印日志
18
+ # 检查是否直接抛错
19
+
20
+ @error = {}
21
+ raise "Responsed nothing from Weixin" if json.nil? && @raise_flag
22
+ if json["errcode"].present? && json["errcode"].to_i != 0
23
+ SimpleWx.logger.error(json)
24
+ @error = json
25
+ raise "Weixin response json with errcode: #{json}" if @raise_flag
26
+ else
27
+ if log_flag
28
+ SimpleWx.logger.info("SimpleWxLog:#{self.class.name} -- #{log_flag} -- #{json}")
29
+ else
30
+ SimpleWx.logger.debug("SimpleWxLog:#{self.class.name} -- #{json}")
31
+ end
32
+ end
33
+ json
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,73 @@
1
+ module SimpleWx
2
+ class Menu < Base
3
+
4
+ ### Usage
5
+ #
6
+ # ---------- class-methods ----------
7
+ #
8
+ # SimpleWx::Menu.show
9
+ # SimpleWx::Menu.create(buttons)
10
+ # => true/false
11
+ # SimpleWx::Menu.delete
12
+ # => true/false
13
+ #
14
+ # ---------- instance-methods -----------
15
+ #
16
+ # menu = SimpleWx::Menu.new
17
+ # menu.show
18
+ #
19
+ # if menu.create(buttons)
20
+ # ...
21
+ # else
22
+ # p menu.error
23
+ # end
24
+ #
25
+ # menu.delete!
26
+ # when "errcode" existed in json of response, it will raise the error:
27
+ # => "Weixin response json with errcode: #{json}"
28
+ #
29
+
30
+ def initialize options = {}
31
+ @access_token = options[:access_token] || AccessToken.access_token
32
+ end
33
+
34
+ def show
35
+ url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=#{@access_token}"
36
+ response = RestClient.get url
37
+ response_json = errcode_check(JSON.parse(response))
38
+ @menus = response_json["menu"]
39
+ end
40
+
41
+ def create menu_hash
42
+ url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=#{@access_token}"
43
+ response = RestClient.post(url, JSON.generate({button: menu_hash}))
44
+ errcode_check(JSON.parse(response))
45
+ @error.blank?
46
+ end
47
+
48
+ def delete
49
+ url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=#{@access_token}"
50
+ response = RestClient.get url
51
+ errcode_check(JSON.parse(response))
52
+ @error.blank?
53
+ end
54
+
55
+ def create! menu_hash
56
+ @raise_flag ||= true
57
+ create menu_hash
58
+ end
59
+
60
+ def delete!
61
+ @raise_flag ||= true
62
+ delete
63
+ end
64
+
65
+ def self.method_missing m, *args
66
+ if instance_methods.include? m.to_sym
67
+ self.new.send(m, *args)
68
+ else
69
+ super
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,59 @@
1
+ module SimpleWx
2
+ class Message < Base
3
+ attr_accessor :openid, :json, :xml
4
+ def initialize options
5
+ @openid = options.delete(:openid)
6
+ @access_token = options.delete(:access_token) || AccessToken.access_token
7
+ @custom_msg_url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=#{@access_token}"
8
+ @json = {}
9
+ @xml = {}
10
+ end
11
+
12
+ protected
13
+
14
+ def set_json
15
+ @json[:touser] = @openid
16
+ end
17
+
18
+ def set_xml
19
+ @xml["ToUserName"] = @openid
20
+ @xml["FromUserName"] = SimpleWx.weixin_config["serial_no"]
21
+ @xml["CreateTime"] = Time.now.to_i.to_s
22
+ end
23
+
24
+ def send_json
25
+ set_json
26
+ response = RestClient.post(@custom_msg_url, JSON.generate(@json))
27
+ errcode_check(JSON.parse(response))
28
+ end
29
+
30
+ def send_json!
31
+ @raise_flag ||= true
32
+ send_json
33
+ end
34
+
35
+ def to_xml
36
+ set_xml
37
+ builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
38
+ xml.xml do
39
+ recursively_xml xml, @xml
40
+ end
41
+ end
42
+ builder.to_xml
43
+ end
44
+
45
+ private
46
+
47
+ def recursively_xml builder, hsh
48
+ hsh.each do |k, v|
49
+ if v.is_a? Hash
50
+ builder.send(k) do
51
+ recursively_xml(builder, v)
52
+ end
53
+ else
54
+ builder.send(k, v)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ module SimpleWx
2
+ module Messages
3
+ class ImageMessage < Message
4
+ def initialize options
5
+ super
6
+ @media_id = options[:media_id]
7
+ end
8
+
9
+ def send_json
10
+ @json[:msgtype] = "image"
11
+ @json[:image] = {media_id: @media_id}
12
+ SimpleWx.logger.info("SimpleWxLog:#{self.class.name} -- #{@openid} -- #{json}")
13
+ super
14
+ end
15
+
16
+ def to_xml
17
+ @xml["MsgType"] = "image"
18
+ @xml["Image"] = { "MediaId" => @media_id }
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module SimpleWx
2
+ module Messages
3
+ class TextMessage < Message
4
+ def initialize options
5
+ super
6
+ @content = options[:content]
7
+ end
8
+
9
+ def send_json
10
+ @json[:msgtype] = "text"
11
+ @json[:text] = {content: @content}
12
+ SimpleWx.logger.info("SimpleWxLog:#{self.class.name} -- #{@openid} -- #{json}")
13
+ super
14
+ end
15
+
16
+ def to_xml
17
+ @xml["MsgType"] = "text"
18
+ @xml["Content"] = @content
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,82 @@
1
+ module SimpleWx
2
+ class OAuth < Base
3
+
4
+ ### Usage
5
+ #
6
+ # auth = SimpleWx::OAuth.new(code: "code")
7
+ #
8
+ # 调用 OAth2 的 access_token 接口, 返回结果信息
9
+ # result_json = auth.get_access_token
10
+ #
11
+ # auth 返回的基本参数会赋值给对象属性
12
+ # auth.access_token == result_json["access_token"]
13
+ # => true
14
+ #
15
+ # 检查 access_token 是否过期
16
+ # auth.access_token_valid?
17
+ # => true
18
+ #
19
+ # auth.expires_in
20
+ # => 7200
21
+ # sleep 7201
22
+ # auth.access_token_valid?
23
+ # => false
24
+ #
25
+ # 刷新access_token接口
26
+ # result_json = auth.refresh_token
27
+ # auth.access_token == result_json["access_token"]
28
+ # auth.access_token_valid?
29
+ # => true
30
+ #
31
+
32
+ attr_reader :code, :scope, :expires_in, :unionid, :result
33
+ attr_accessor :access_token, :refresh_token, :openid
34
+
35
+ def initialize options
36
+ @code = options[:code]
37
+ end
38
+
39
+ def get_access_token
40
+ url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=#{SimpleWx.weixin_config["app_id"]}&secret=#{SimpleWx.weixin_config["app_secret"]}&code=#{@code}&grant_type=authorization_code"
41
+ response = RestClient.get url
42
+ set_result(errcode_check(JSON.parse(response)))
43
+ end
44
+
45
+ def get_user_info
46
+ UserInfo.get_auth_info(o_auth: self)
47
+ end
48
+
49
+ def access_token_valid?
50
+ url = "https://api.weixin.qq.com/sns/auth?access_token=#{@access_token}&openid=#{@openid}"
51
+ response = RestClient.get url
52
+ errcode_check(JSON.parse(response))
53
+ @error.blank?
54
+ end
55
+
56
+ def refresh_token
57
+ url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=#{SimpleWx.weixin_config["app_id"]}&grant_type=refresh_token&refresh_token=#{@refresh_token}"
58
+ response = RestClient.get url
59
+ set_result(errcode_check(JSON.parse(response)))
60
+ end
61
+
62
+ def self.generate_auth_link url, state = "", scope = "snsapi_userinfo"
63
+ params = {
64
+ appid: SimpleWx.weixin_config["app_id"],
65
+ redirect_uri: url,
66
+ response_type: "code",
67
+ scope: scope,
68
+ state: state
69
+ }
70
+ "https://open.weixin.qq.com/connect/oauth2/authorize?#{params.to_query}#wechat_redirect"
71
+ end
72
+
73
+ private
74
+
75
+ def set_result result
76
+ result.each do |k, v|
77
+ instance_variable_set "@#{k}", v
78
+ end
79
+ @result = result
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,31 @@
1
+ module SimpleWx
2
+ class Signaturer < Base
3
+
4
+ ### Usage
5
+ #
6
+ # signer = SimpleWx::Signaturer.new timestamp: params[:timestamp], nonce: params[:nonce]
7
+ # if signer.sign params[:signature]
8
+ # render text: params[:echostr]
9
+ # else
10
+ # ...
11
+ # end
12
+
13
+ def initialize options = {}
14
+ @timestamp = options.fetch :timestamp
15
+ @nonce = options.fetch :nonce
16
+ @token = SimpleWx.weixin_config["token"] #TODO 没有就raise错误,用method_missing
17
+ end
18
+
19
+ def sign signture
20
+ @sort_array = [@timestamp, @nonce, @token].sort
21
+ signture == sha1_encrypt
22
+ end
23
+
24
+ private
25
+
26
+ def sha1_encrypt
27
+ encrypt_str = @sort_array.join
28
+ Digest::SHA1.hexdigest(encrypt_str)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ module SimpleWx
2
+ class UserInfo < Base
3
+
4
+ ### Usage
5
+ #
6
+ # ---------- class-methods ----------
7
+ #
8
+ # instance_of_oauth = SimpleWx::OAuth.new("code")
9
+ # instance_of_oauth.get_access_token
10
+ # user_info_hsh = SimpleWx::UserInfo.get_auth_info(o_auth: instance_of_oauth)
11
+ #
12
+ # user_info_hsh = SimpleWx::UserInfo.get_basic_info(access_token: "token", openid: "openid")
13
+ #
14
+ # ---------- instance-methods -----------
15
+ #
16
+ # @user_info = SimpleWx::UserInfo.new(access_token: "token", openid: "openid")
17
+ # user_info_hsh = @user_info.get_basic_info
18
+ # if @user_info.error.present?
19
+ # ...
20
+ # end
21
+ #
22
+
23
+ def initialize options
24
+ @openid = options[:openid]
25
+ @o_auth = options[:o_auth]
26
+ @access_token = options[:access_token] || AccessToken.access_token
27
+ end
28
+
29
+ def get_basic_info
30
+ url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=#{@access_token}&openid=#{@openid}&lang=zh_CN"
31
+ response = RestClient.get url
32
+ errcode_check(JSON.parse(response))
33
+ end
34
+
35
+ def get_auth_info
36
+ url = "https://api.weixin.qq.com/sns/userinfo?access_token=#{@o_auth.access_token}&openid=#{@o_auth.openid}&lang=zh_CN"
37
+ response = RestClient.get url
38
+ errcode_check(JSON.parse(response))
39
+ end
40
+
41
+ def self.method_missing m, hsh
42
+ if instance_methods.include? m.to_sym
43
+ self.new(hsh).send m
44
+ else
45
+ super
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleWx
2
+ VERSION = "0.0.0"
3
+ end
data/lib/simple_wx.rb ADDED
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ require 'redis'
3
+ require 'yell'
4
+
5
+ module SimpleWx
6
+ @@weixin_config = {}
7
+ @@logger = Yell.new :datefile, 'simple_wx.log'
8
+ @@redis = Redis.new(host: '127.0.0.1', port: '6379', db: '0')
9
+
10
+ def self.weixin_config
11
+ @@weixin_config
12
+ end
13
+
14
+ def self.logger
15
+ @@logger
16
+ end
17
+
18
+ def self.redis
19
+ @@redis
20
+ end
21
+ end
22
+
23
+ require 'simple_wx/base'
24
+ require 'simple_wx/signaturer'
25
+ require 'simple_wx/access_token'
26
+ require 'simple_wx/menu'
27
+ require 'simple_wx/user_info'
28
+ require 'simple_wx/message'
29
+ require 'simple_wx/messages/text_message'
30
+ require 'simple_wx/messages/image_message'
31
+
data/simple_wx.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simple_wx/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "simple_wx"
8
+ spec.version = SimpleWx::VERSION
9
+ spec.authors = ["Scott1743"]
10
+ spec.email = ["512981271@qq.com"]
11
+ spec.summary = ""
12
+ spec.description = %q{Ruby Api for WeiXin}
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'redis', '~> 3.2.1'
21
+ spec.add_dependency 'yell', '~> 2.0.0'
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+
25
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_wx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Scott1743
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: yell
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ description: Ruby Api for WeiXin
56
+ email:
57
+ - 512981271@qq.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - README.md
64
+ - config/initializers/simple_wx.rb.example
65
+ - lib/simple_wx.rb
66
+ - lib/simple_wx/access_token.rb
67
+ - lib/simple_wx/base.rb
68
+ - lib/simple_wx/menu.rb
69
+ - lib/simple_wx/message.rb
70
+ - lib/simple_wx/messages/image_message.rb
71
+ - lib/simple_wx/messages/text_message.rb
72
+ - lib/simple_wx/o_auth.rb
73
+ - lib/simple_wx/signaturer.rb
74
+ - lib/simple_wx/user_info.rb
75
+ - lib/simple_wx/version.rb
76
+ - simple_wx.gemspec
77
+ homepage:
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.2.2
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: ''
101
+ test_files: []