weixin_rails_middleware 1.2.2 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/weixin_rails_middleware/weixin_controller.rb +13 -1
- data/config/routes.rb +1 -1
- data/lib/generators/templates/weixin_controller.rb +49 -45
- data/lib/weixin_rails_middleware.rb +4 -1
- data/lib/weixin_rails_middleware/adapter/multiple_public_account.rb +18 -20
- data/lib/weixin_rails_middleware/adapter/single_public_account.rb +17 -19
- data/lib/weixin_rails_middleware/adapter/weixin_adapter.rb +53 -55
- data/lib/weixin_rails_middleware/helpers/reply_weixin_message_helper.rb +16 -4
- data/lib/weixin_rails_middleware/version.rb +1 -1
- metadata +2 -17
- data/lib/weixin_rails_middleware/adapter.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8b512a640cd72d5b60a38fc9ecd29cc36c045c1
|
4
|
+
data.tar.gz: e9ce1f55233f8fa3e7c9ab84276001eac83d6d8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e95b2b9e4c0668bef289e2f2dd1b9f5b125e11725bf0fcdfcca423f433a1f204319ac829a1438a4f0dd813142fdc81ce7ad92b4d7088f06c252834473f89ee20
|
7
|
+
data.tar.gz: e750d71896700712fd8609987f33086155f1bd46d204b8763ca91e971f5b569cbae972f82b171ca5e033634c48e3f32e465bf55bcad53c2d13446360b6599399
|
@@ -5,6 +5,7 @@ module WeixinRailsMiddleware
|
|
5
5
|
skip_before_filter :verify_authenticity_token
|
6
6
|
before_filter :initialize_adapter, :check_weixin_legality, only: [:index, :reply]
|
7
7
|
before_filter :set_weixin_public_account, :set_weixin_message, only: :reply
|
8
|
+
before_filter :set_keyword, only: :reply
|
8
9
|
|
9
10
|
def index
|
10
11
|
end
|
@@ -15,7 +16,7 @@ module WeixinRailsMiddleware
|
|
15
16
|
protected
|
16
17
|
|
17
18
|
def initialize_adapter
|
18
|
-
@weixin_adapter ||=
|
19
|
+
@weixin_adapter ||= WexinAdapter.init_with(params)
|
19
20
|
end
|
20
21
|
|
21
22
|
def check_weixin_legality
|
@@ -36,5 +37,16 @@ module WeixinRailsMiddleware
|
|
36
37
|
@weixin_message ||= Message.factory(request.body.read)
|
37
38
|
end
|
38
39
|
|
40
|
+
def set_keyword
|
41
|
+
@keyword = @weixin_message.Content || # 文本消息
|
42
|
+
@weixin_message.EventKey || # 事件推送
|
43
|
+
@weixin_message.Recognition # 接收语音识别结果
|
44
|
+
end
|
45
|
+
|
46
|
+
# http://apidock.com/rails/ActionController/Base/default_url_options
|
47
|
+
def default_url_options(options={})
|
48
|
+
{ weichat_id: @weixin_message.FromUserName }
|
49
|
+
end
|
50
|
+
|
39
51
|
end
|
40
52
|
end
|
data/config/routes.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
# 1:
|
3
|
-
# @
|
4
|
-
#
|
5
|
-
# @weixin_public_account
|
2
|
+
# 1, @weixin_message: 获取微信所有参数.
|
3
|
+
# 2, @weixin_public_account: 如果配置了public_account_class选项,则会返回当前实例,否则返回nil.
|
4
|
+
# 3, @keyword: 目前微信只有这三种情况存在关键字: 文本消息, 事件推送, 接收语音识别结果
|
6
5
|
WeixinRailsMiddleware::WeixinController.class_eval do
|
7
|
-
before_filter :set_keyword, only: :reply
|
8
6
|
|
9
7
|
def reply
|
10
8
|
render xml: send("response_#{@weixin_message.MsgType}_message", {})
|
@@ -31,9 +29,9 @@ WeixinRailsMiddleware::WeixinController.class_eval do
|
|
31
29
|
# <PicUrl><![CDATA[this is a url]]></PicUrl>
|
32
30
|
# <MediaId><![CDATA[media_id]]></MediaId>
|
33
31
|
def response_image_message(options={})
|
34
|
-
@pic_url = @weixin_message.PicUrl
|
35
32
|
@media_id = @weixin_message.MediaId # 可以调用多媒体文件下载接口拉取数据。
|
36
|
-
|
33
|
+
@pic_url = @weixin_message.PicUrl # 也可以直接通过此链接下载图片, 建议使用carrierwave.
|
34
|
+
reply_image_message(generate_image(@media_id))
|
37
35
|
end
|
38
36
|
|
39
37
|
# <Title><![CDATA[公众平台官网链接]]></Title>
|
@@ -46,40 +44,14 @@ WeixinRailsMiddleware::WeixinController.class_eval do
|
|
46
44
|
reply_text_message("回复链接信息")
|
47
45
|
end
|
48
46
|
|
49
|
-
def response_event_message(options={})
|
50
|
-
event_type = @weixin_message.Event
|
51
|
-
case event_type
|
52
|
-
when "subscribe" # 关注公众账号
|
53
|
-
if @keyword.present?
|
54
|
-
# 扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送
|
55
|
-
return reply_text_message("扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送, keyword: #{@keyword}")
|
56
|
-
end
|
57
|
-
reply_text_message("关注公众账号")
|
58
|
-
when "unsubscribe" # 取消关注
|
59
|
-
reply_text_message("取消关注")
|
60
|
-
when "SCAN" # 扫描带参数二维码事件: 2用户已关注时的事件推送
|
61
|
-
reply_text_message("扫描带参数二维码事件: 2用户已关注时的事件推送, keyword: #{@keyword}")
|
62
|
-
when "LOCATION" # 上报地理位置事件
|
63
|
-
@lat = @weixin_message.Latitude
|
64
|
-
@lgt = @weixin_message.Longitude
|
65
|
-
@precision = @weixin_message.Precision
|
66
|
-
reply_text_message("Your Location: #{@lat}, #{@lgt}, #{@precision}")
|
67
|
-
when "CLICK" # 点击菜单拉取消息时的事件推送
|
68
|
-
reply_text_message("你点击了: #{@keyword}")
|
69
|
-
when "VIEW" # 点击菜单跳转链接时的事件推送
|
70
|
-
reply_text_message("你点击了: #{@keyword}")
|
71
|
-
else
|
72
|
-
reply_text_message("处理无法识别的事件")
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
47
|
# <MediaId><![CDATA[media_id]]></MediaId>
|
78
48
|
# <Format><![CDATA[Format]]></Format>
|
79
49
|
def response_voice_message(options={})
|
80
50
|
@media_id = @weixin_message.MediaId # 可以调用多媒体文件下载接口拉取数据。
|
81
51
|
@format = @weixin_message.Format
|
82
|
-
|
52
|
+
# 如果开启了语音翻译功能,@keyword则为翻译的结果
|
53
|
+
# reply_text_message("回复语音信息: #{@keyword}")
|
54
|
+
reply_voice_message(generate_voice(@media_id))
|
83
55
|
end
|
84
56
|
|
85
57
|
# <MediaId><![CDATA[media_id]]></MediaId>
|
@@ -91,15 +63,47 @@ WeixinRailsMiddleware::WeixinController.class_eval do
|
|
91
63
|
reply_text_message("回复视频信息")
|
92
64
|
end
|
93
65
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
@weixin_message.EventKey || # 事件推送
|
98
|
-
@weixin_message.Recognition # 接收语音识别结果
|
66
|
+
def response_event_message(options={})
|
67
|
+
event_type = @weixin_message.Event
|
68
|
+
send("reply_#{event_type.downcase}_event")
|
99
69
|
end
|
100
70
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
71
|
+
private
|
72
|
+
|
73
|
+
# 关注公众账号
|
74
|
+
def reply_subscribe_event
|
75
|
+
if @keyword.present?
|
76
|
+
# 扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送
|
77
|
+
return reply_text_message("扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送, keyword: #{@keyword}")
|
78
|
+
end
|
79
|
+
reply_text_message("关注公众账号")
|
80
|
+
end
|
81
|
+
|
82
|
+
# 取消关注
|
83
|
+
def reply_unsubscribe_event
|
84
|
+
Rails.logger.info("取消关注")
|
85
|
+
end
|
86
|
+
|
87
|
+
# 扫描带参数二维码事件: 2. 用户已关注时的事件推送
|
88
|
+
def reply_scan_event
|
89
|
+
reply_text_message("扫描带参数二维码事件: 2. 用户已关注时的事件推送, keyword: #{@keyword}")
|
90
|
+
end
|
91
|
+
|
92
|
+
def reply_location_event # 上报地理位置事件
|
93
|
+
@lat = @weixin_message.Latitude
|
94
|
+
@lgt = @weixin_message.Longitude
|
95
|
+
@precision = @weixin_message.Precision
|
96
|
+
reply_text_message("Your Location: #{@lat}, #{@lgt}, #{@precision}")
|
97
|
+
end
|
98
|
+
|
99
|
+
# 点击菜单拉取消息时的事件推送
|
100
|
+
def reply_click_event
|
101
|
+
reply_text_message("你点击了: #{@keyword}")
|
102
|
+
end
|
103
|
+
|
104
|
+
# 点击菜单跳转链接时的事件推送
|
105
|
+
def reply_view_event
|
106
|
+
Rails.logger.info("你点击了: #{@keyword}")
|
107
|
+
end
|
108
|
+
|
105
109
|
end
|
@@ -4,11 +4,14 @@ require "weixin_rails_middleware/models/message"
|
|
4
4
|
require "weixin_rails_middleware/models/reply_message"
|
5
5
|
require "weixin_rails_middleware/helpers/reply_weixin_message_helper"
|
6
6
|
require "weixin_rails_middleware/helpers/unique_token_helper"
|
7
|
-
require "weixin_rails_middleware/adapter"
|
8
7
|
require "weixin_rails_middleware/helpers/auto_generate_weixin_token_secret_key"
|
9
8
|
|
10
9
|
module WeixinRailsMiddleware
|
11
10
|
|
11
|
+
autoload(:WexinAdapter, "weixin_rails_middleware/adapter/weixin_adapter")
|
12
|
+
autoload(:SinglePublicAccount, "weixin_rails_middleware/adapter/single_public_account")
|
13
|
+
autoload(:MultiplePublicAccount, "weixin_rails_middleware/adapter/multiple_public_account")
|
14
|
+
|
12
15
|
DEFAULT_TOKEN_COLUMN_NAME = "weixin_token".freeze
|
13
16
|
DEFAULT_WEIXIN_SECRET_KEY = "weixin_secret_key".freeze
|
14
17
|
|
@@ -1,30 +1,28 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module WeixinRailsMiddleware
|
3
|
-
|
4
|
-
class MultiplePublicAccount < WexinAdapter
|
3
|
+
class MultiplePublicAccount < WexinAdapter
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# check the token from Weixin Service is exist in local store.
|
12
|
-
def is_weixin_secret_key_valid?
|
13
|
-
current_weixin_public_account.present?
|
14
|
-
end
|
5
|
+
def check_weixin_legality
|
6
|
+
return render_authorize_result(404) if !is_weixin_secret_key_valid?
|
7
|
+
super
|
8
|
+
end
|
15
9
|
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
# check the token from Weixin Service is exist in local store.
|
11
|
+
def is_weixin_secret_key_valid?
|
12
|
+
current_weixin_public_account.present?
|
13
|
+
end
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
def current_weixin_token
|
16
|
+
current_weixin_public_account.try(DEFAULT_TOKEN_COLUMN_NAME)
|
17
|
+
end
|
23
18
|
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
def current_weixin_public_account
|
20
|
+
self.class.token_model_class.where("#{DEFAULT_WEIXIN_SECRET_KEY}" => weixin_secret_key).first
|
21
|
+
end
|
27
22
|
|
23
|
+
def error_msg
|
24
|
+
"#{__FILE__}:#{__LINE__}: RecordNotFound - Couldn't find #{self.class.token_model} with weixin_secret_key=#{weixin_secret_key}"
|
28
25
|
end
|
26
|
+
|
29
27
|
end
|
30
28
|
end
|
@@ -1,29 +1,27 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module WeixinRailsMiddleware
|
3
|
-
|
4
|
-
class SinglePublicAccount < WexinAdapter
|
3
|
+
class SinglePublicAccount < WexinAdapter
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def is_weixin_secret_key_valid?
|
12
|
-
weixin_secret_key == self.class.weixin_secret_string
|
13
|
-
end
|
5
|
+
def check_weixin_legality
|
6
|
+
return render_authorize_result if !is_weixin_secret_key_valid?
|
7
|
+
super
|
8
|
+
end
|
14
9
|
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
def is_weixin_secret_key_valid?
|
11
|
+
weixin_secret_key == self.class.weixin_secret_string
|
12
|
+
end
|
18
13
|
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
def current_weixin_token
|
15
|
+
self.class.weixin_token_string
|
16
|
+
end
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
def current_weixin_public_account
|
19
|
+
nil
|
20
|
+
end
|
26
21
|
|
22
|
+
def error_msg
|
23
|
+
"#{__FILE__}:#{__LINE__}: Weixin secret string NotMatch."
|
27
24
|
end
|
25
|
+
|
28
26
|
end
|
29
27
|
end
|
@@ -1,74 +1,72 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module WeixinRailsMiddleware
|
3
|
-
|
4
|
-
|
5
|
-
extend ConfigurationHelpers
|
3
|
+
class WexinAdapter
|
4
|
+
extend ConfigurationHelpers
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
attr_accessor :signature, :timestamp, :nonce, :echostr
|
7
|
+
attr_accessor :weixin_secret_key
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
def initialize(weixin_params)
|
10
|
+
@weixin_secret_key = weixin_params[:weixin_secret_key]
|
11
|
+
# 以下参数为什么加空字符串默认值的原因:
|
12
|
+
# SB微信偶尔会再重新发一次get请求,但是不会带上signature,timestamp,nonce的参数
|
13
|
+
# 一个预防措施吧。
|
14
|
+
@signature = weixin_params[:signature] || ''
|
15
|
+
@timestamp = weixin_params[:timestamp] || ''
|
16
|
+
@nonce = weixin_params[:nonce] || ''
|
17
|
+
@echostr = weixin_params[:echostr] || ''
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
20
|
+
def self.init_with(weixin_params)
|
21
|
+
if weixin_token_string.present?
|
22
|
+
SinglePublicAccount.new(weixin_params)
|
23
|
+
else
|
24
|
+
MultiplePublicAccount.new(weixin_params)
|
27
25
|
end
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
def check_weixin_legality
|
29
|
+
return render_authorize_result(403, self.class.error_msg) if !is_signature_valid?
|
30
|
+
render_authorize_result(200, echostr, true)
|
31
|
+
end
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
def is_signature_valid?
|
34
|
+
sort_params = [current_weixin_token, timestamp, nonce].sort.join
|
35
|
+
current_signature = Digest::SHA1.hexdigest(sort_params)
|
36
|
+
return true if current_signature == signature
|
37
|
+
false
|
38
|
+
end
|
40
39
|
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
def current_weixin_public_account
|
41
|
+
raise NotImplementedError, "Subclasses must implement current_weixin_public_account method"
|
42
|
+
end
|
44
43
|
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
def current_weixin_token
|
45
|
+
raise NotImplementedError, "Subclasses must implement current_weixin_token method"
|
46
|
+
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
def is_weixin_secret_key_valid?
|
49
|
+
raise NotImplementedError, "Subclasses must implement is_weixin_secret_key_valid? method"
|
50
|
+
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
52
|
+
class << self
|
53
|
+
def error_msg
|
54
|
+
"#{__FILE__}:#{__LINE__}: Weixin signature NotMatch"
|
57
55
|
end
|
56
|
+
end
|
58
57
|
|
59
|
-
|
58
|
+
private
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
60
|
+
# render weixin server authorize results
|
61
|
+
def render_authorize_result(status=403, text=nil, valid=false)
|
62
|
+
text = text || error_msg
|
63
|
+
Rails.logger.error(text) if status != 200
|
64
|
+
{text: text, status: status, valid: valid}
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
def error_msg
|
68
|
+
self.class.error_msg
|
69
|
+
end
|
71
70
|
|
72
|
-
end
|
73
71
|
end
|
74
72
|
end
|
@@ -51,13 +51,25 @@ module WeixinRailsMiddleware
|
|
51
51
|
|
52
52
|
def generate_video(media_id, desc, title)
|
53
53
|
video = Video.new
|
54
|
-
video.MediaId
|
54
|
+
video.MediaId = media_id
|
55
|
+
video.Title = title
|
55
56
|
video.Description = desc
|
56
|
-
video
|
57
|
-
vodeo
|
57
|
+
video
|
58
58
|
end
|
59
59
|
|
60
|
-
|
60
|
+
# <xml>
|
61
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
62
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
63
|
+
# <CreateTime>12345678</CreateTime>
|
64
|
+
# <MsgType><![CDATA[video]]></MsgType>
|
65
|
+
# <Video>
|
66
|
+
# <MediaId><![CDATA[media_id]]></MediaId>
|
67
|
+
# <Title><![CDATA[title]]></Title>
|
68
|
+
# <Description><![CDATA[description]]></Description>
|
69
|
+
# </Video>
|
70
|
+
# </xml>
|
71
|
+
|
72
|
+
def reply_video_message(from=nil, to=nil, video)
|
61
73
|
message = VideoReplyMessage.new
|
62
74
|
message.FromUserName = from || @weixin_message.ToUserName
|
63
75
|
message.ToUserName = to || @weixin_message.FromUserName
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: weixin_rails_middleware
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lanrion
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.1'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: multi_json
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - '>='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 1.9.0
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - '>='
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 1.9.0
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: multi_xml
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,7 +97,6 @@ files:
|
|
111
97
|
- lib/generators/weixin_rails_middleware/install_generator.rb
|
112
98
|
- lib/generators/weixin_rails_middleware/migration_generator.rb
|
113
99
|
- lib/weixin_rails_middleware.rb
|
114
|
-
- lib/weixin_rails_middleware/adapter.rb
|
115
100
|
- lib/weixin_rails_middleware/adapter/multiple_public_account.rb
|
116
101
|
- lib/weixin_rails_middleware/adapter/single_public_account.rb
|
117
102
|
- lib/weixin_rails_middleware/adapter/weixin_adapter.rb
|