weixin_rails_middleware 1.0.0
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/Rakefile +34 -0
- data/app/controllers/weixin_rails_middleware/application_controller.rb +4 -0
- data/app/controllers/weixin_rails_middleware/weixin_controller.rb +63 -0
- data/config/routes.rb +4 -0
- data/lib/generators/templates/initializer.rb +20 -0
- data/lib/generators/templates/weixin_controller.rb +27 -0
- data/lib/generators/weixin_rails_middleware/install_generator.rb +35 -0
- data/lib/tasks/weixin_rails_middleware_tasks.rake +4 -0
- data/lib/weixin_rails_middleware.rb +27 -0
- data/lib/weixin_rails_middleware/configuration.rb +22 -0
- data/lib/weixin_rails_middleware/engine.rb +5 -0
- data/lib/weixin_rails_middleware/message.rb +160 -0
- data/lib/weixin_rails_middleware/reply_message.rb +183 -0
- data/lib/weixin_rails_middleware/version.rb +3 -0
- data/lib/weixin_rails_middleware/weixin_message_helper.rb +97 -0
- metadata +143 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 3460a9d1f7aa1a3e99fdc92ce50d3b225553a999
|
|
4
|
+
data.tar.gz: 045d5b32cbbe7ac1ad175d08d27495dd60360f5c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 985aa7b06a951dda574c72500ecec59a2dd001ac82eef9af4c1e3b6e583188da06604b39e24f100a54a0c5d9e2116edc275c4dcac6ae1c9b3527d7e825fc9f01
|
|
7
|
+
data.tar.gz: a2c2ef8e8899dec3945310add57afbc0f8bd798e31c83f3ae150d9e7523f12b39c2eff5a97ea13db888e65a80b9b16aeaa74016cccf37bb8f911402eae7efa9a
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2014 YOURNAME
|
|
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/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 = 'WeixinRailsMiddleware'
|
|
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
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module WeixinRailsMiddleware
|
|
2
|
+
class WeixinController < ApplicationController
|
|
3
|
+
|
|
4
|
+
include WeixinMessageHelper
|
|
5
|
+
|
|
6
|
+
skip_before_filter :verify_authenticity_token
|
|
7
|
+
before_action :check_weixin_params, only: [:index, :reply]
|
|
8
|
+
|
|
9
|
+
def index
|
|
10
|
+
render text: params[:echostr]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def reply
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
def check_weixin_params
|
|
19
|
+
if check_weixin_token_valid?
|
|
20
|
+
if !is_hexdigest?
|
|
21
|
+
render text: "Forbidden", status: 403
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# check the token from Weixin Service is exist in local store.
|
|
27
|
+
def check_weixin_token_valid?
|
|
28
|
+
if WeixinRailsMiddleware.config.token_string.blank?
|
|
29
|
+
if token_model_instance.blank?
|
|
30
|
+
render text: "Forbidden", status: 403
|
|
31
|
+
return false
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
if current_weixin_token != WeixinRailsMiddleware.config.token_string
|
|
35
|
+
render text: "Forbidden", status: 403
|
|
36
|
+
return false
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def is_hexdigest?
|
|
43
|
+
signature = params[:signature] || ''
|
|
44
|
+
timestamp = params[:timestamp] || ''
|
|
45
|
+
nonce = params[:nonce] || ''
|
|
46
|
+
current_signature = Digest::SHA1.hexdigest([current_weixin_token, timestamp, nonce].sort.join)
|
|
47
|
+
return true if current_signature == signature
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def current_weixin_token
|
|
52
|
+
@weixin_token = params[:weixin_token]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def token_model_instance
|
|
56
|
+
token_model = WeixinRailsMiddleware.config.token_model_class
|
|
57
|
+
token_column = WeixinRailsMiddleware.config.token_column
|
|
58
|
+
token_model_instance = token_model.where("#{token_column}" => current_weixin_token).first
|
|
59
|
+
token_model_instance
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Use this hook to configure WeixinRailsMiddleware bahaviors.
|
|
2
|
+
WeixinRailsMiddleware.configure do |config|
|
|
3
|
+
|
|
4
|
+
## NOTE:
|
|
5
|
+
## if you config all them, it will use `token_string` default
|
|
6
|
+
##
|
|
7
|
+
# Th FIRST configure
|
|
8
|
+
# if you config `token_model`, it will use it to find_by_weixin_token
|
|
9
|
+
# you must config a column name, `weixin_token` default
|
|
10
|
+
# config.token_model = "" # ActiveRecord subclass or other ORM subclass
|
|
11
|
+
# config.token_column = "weixin_token"
|
|
12
|
+
|
|
13
|
+
# OR the SECOND configure
|
|
14
|
+
# if you config `token_string`, so it will directly use it
|
|
15
|
+
# config.token_string = "token string"
|
|
16
|
+
|
|
17
|
+
# router
|
|
18
|
+
config.engine_path = "/"
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
WeixinRailsMiddleware::WeixinController.class_eval do
|
|
2
|
+
|
|
3
|
+
def reply
|
|
4
|
+
# Get the current_message
|
|
5
|
+
current_message = current_weixin_message
|
|
6
|
+
|
|
7
|
+
case current_message.MsgType
|
|
8
|
+
when 'text'
|
|
9
|
+
# text message handler
|
|
10
|
+
# render xml: reply_text_message("ToUserName", "FromUserName", "your Message")
|
|
11
|
+
when 'image'
|
|
12
|
+
# image message handler
|
|
13
|
+
when 'location'
|
|
14
|
+
# location message handler
|
|
15
|
+
when 'link'
|
|
16
|
+
# link message handler
|
|
17
|
+
when 'event'
|
|
18
|
+
# event messge handler
|
|
19
|
+
when 'voice'
|
|
20
|
+
# voice message handler
|
|
21
|
+
when 'video'
|
|
22
|
+
# video message handler
|
|
23
|
+
else
|
|
24
|
+
render xml: reply_text_message(current_message.ToUserName, current_message.FromUserName, 'Unknow message')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Rails::Generators::Base dont need a name
|
|
2
|
+
# Rails::Generators::NamedBase need a name
|
|
3
|
+
module WeixinRailsMiddleware
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path('../../templates', __FILE__)
|
|
7
|
+
|
|
8
|
+
desc 'Creates a Dashing initializer for your application.'
|
|
9
|
+
|
|
10
|
+
def install
|
|
11
|
+
route 'mount WeixinRailsMiddleware::Engine, at: WeixinRailsMiddleware.config.engine_path'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def copy_initializer
|
|
15
|
+
template 'initializer.rb', 'config/initializers/weixin_rails_middleware.rb'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def configure_application
|
|
19
|
+
application <<-APP
|
|
20
|
+
config.to_prepare do
|
|
21
|
+
# Load application's model / class decorators
|
|
22
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
|
|
23
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
APP
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def copy_decorators
|
|
30
|
+
template 'weixin_controller.rb', 'app/decorators/controllers/weixin_rails_middleware/weixin_controller_decorator.rb'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require "weixin_rails_middleware/engine"
|
|
2
|
+
require "weixin_rails_middleware/configuration"
|
|
3
|
+
require "weixin_rails_middleware/message"
|
|
4
|
+
require "weixin_rails_middleware/reply_message"
|
|
5
|
+
require "weixin_rails_middleware/weixin_message_helper"
|
|
6
|
+
|
|
7
|
+
module WeixinRailsMiddleware
|
|
8
|
+
|
|
9
|
+
DEFAULT_TOKEN_COLUMN_NAME = "weixin_token".freeze
|
|
10
|
+
DEFAULT_ENGINE_PATH = "/weixin_rails".freeze
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
|
|
14
|
+
attr_accessor :configuration
|
|
15
|
+
|
|
16
|
+
def config
|
|
17
|
+
self.configuration ||= Configuration.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def configure
|
|
21
|
+
yield config if block_given?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module WeixinRailsMiddleware
|
|
2
|
+
class Configuration
|
|
3
|
+
# use 'token_model': if the token is saved in SomeModel, then find token by it
|
|
4
|
+
# use 'token_string': if the token is a String, just use it,
|
|
5
|
+
attr_accessor :token_model, :token_column, :token_string, :engine_path
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@engine_path = DEFAULT_ENGINE_PATH
|
|
9
|
+
@token_column = DEFAULT_TOKEN_COLUMN_NAME
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def token_model_class
|
|
13
|
+
raise "You need to config `token_model` in config/initializers/weixin_rails_middleware.rb" if token_model.blank?
|
|
14
|
+
token_model_c = token_model.constantize
|
|
15
|
+
unless token_model_c.table_exists?
|
|
16
|
+
raise "You don't have #{token_model_c.table_name} table"
|
|
17
|
+
end
|
|
18
|
+
token_model_c
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
# ref: https://github.com/wolfg1969/rack-weixin/lib/weixin/model.rb
|
|
3
|
+
require 'roxml'
|
|
4
|
+
require 'multi_xml'
|
|
5
|
+
require 'ostruct'
|
|
6
|
+
|
|
7
|
+
module WeixinRailsMiddleware
|
|
8
|
+
|
|
9
|
+
class Message
|
|
10
|
+
|
|
11
|
+
def initialize(hash)
|
|
12
|
+
@source = OpenStruct.new(hash)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def method_missing(method, *args, &block)
|
|
16
|
+
@source.send(method, *args, &block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def CreateTime
|
|
20
|
+
@source.CreateTime.to_i
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def MsgId
|
|
24
|
+
@source.MsgId.to_i
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def Message.factory(xml)
|
|
28
|
+
hash = MultiXml.parse(xml)['xml']
|
|
29
|
+
case hash['MsgType']
|
|
30
|
+
when 'text'
|
|
31
|
+
TextMessage.new(hash)
|
|
32
|
+
when 'image'
|
|
33
|
+
ImageMessage.new(hash)
|
|
34
|
+
when 'location'
|
|
35
|
+
LocationMessage.new(hash)
|
|
36
|
+
when 'link'
|
|
37
|
+
LinkMessage.new(hash)
|
|
38
|
+
when 'event'
|
|
39
|
+
EventMessage.new(hash)
|
|
40
|
+
when 'voice'
|
|
41
|
+
VoiceMessage.new(hash)
|
|
42
|
+
when 'video'
|
|
43
|
+
VideoMessage.new(hash)
|
|
44
|
+
else
|
|
45
|
+
raise ArgumentError, 'Unknown Message'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# <xml>
|
|
52
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
53
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
54
|
+
# <CreateTime>1348831860</CreateTime>
|
|
55
|
+
# <MsgType><![CDATA[text]]></MsgType>
|
|
56
|
+
# <Content><![CDATA[this is a test]]></Content>
|
|
57
|
+
# <MsgId>1234567890123456</MsgId>
|
|
58
|
+
# </xml>
|
|
59
|
+
TextMessage = Class.new(Message)
|
|
60
|
+
|
|
61
|
+
# <xml>
|
|
62
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
63
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
64
|
+
# <CreateTime>1348831860</CreateTime>
|
|
65
|
+
# <MsgType><![CDATA[image]]></MsgType>
|
|
66
|
+
# <PicUrl><![CDATA[this is a url]]></PicUrl>
|
|
67
|
+
# <MsgId>1234567890123456</MsgId>
|
|
68
|
+
# </xml>
|
|
69
|
+
ImageMessage = Class.new(Message)
|
|
70
|
+
|
|
71
|
+
# <xml>
|
|
72
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
73
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
74
|
+
# <CreateTime>1351776360</CreateTime>
|
|
75
|
+
# <MsgType><![CDATA[link]]></MsgType>
|
|
76
|
+
# <Title><![CDATA[公众平台官网链接]]></Title>
|
|
77
|
+
# <Description><![CDATA[公众平台官网链接]]></Description>
|
|
78
|
+
# <Url><![CDATA[url]]></Url>
|
|
79
|
+
# <MsgId>1234567890123456</MsgId>
|
|
80
|
+
# </xml>
|
|
81
|
+
LinkMessage = Class.new(Message)
|
|
82
|
+
|
|
83
|
+
# <xml>
|
|
84
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
85
|
+
# <FromUserName><![CDATA[FromUser]]></FromUserName>
|
|
86
|
+
# <CreateTime>123456789</CreateTime>
|
|
87
|
+
# <MsgType><![CDATA[event]]></MsgType>
|
|
88
|
+
# <Event><![CDATA[EVENT]]></Event>
|
|
89
|
+
# <EventKey><![CDATA[EVENTKEY]]></EventKey>
|
|
90
|
+
# </xml>
|
|
91
|
+
EventMessage = Class.new(Message)
|
|
92
|
+
|
|
93
|
+
# <xml>
|
|
94
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
95
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
96
|
+
# <CreateTime>1351776360</CreateTime>
|
|
97
|
+
# <MsgType><![CDATA[location]]></MsgType>
|
|
98
|
+
# <Location_X>23.134521</Location_X>
|
|
99
|
+
# <Location_Y>113.358803</Location_Y>
|
|
100
|
+
# <Scale>20</Scale>
|
|
101
|
+
# <Label><![CDATA[位置信息]]></Label>
|
|
102
|
+
# <MsgId>1234567890123456</MsgId>
|
|
103
|
+
# </xml>
|
|
104
|
+
class LocationMessage < Message
|
|
105
|
+
|
|
106
|
+
def Location_X
|
|
107
|
+
@source.Location_X.to_f
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def Location_Y
|
|
111
|
+
@source.Location_Y.to_f
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def Scale
|
|
115
|
+
@source.Scale.to_i
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# <xml>
|
|
120
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
121
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
122
|
+
# <CreateTime>1376632760</CreateTime>
|
|
123
|
+
# <MsgType><![CDATA[voice]]></MsgType>
|
|
124
|
+
# <MediaId><![CDATA[Qyb0tgux6QLjhL6ipvFZJ-kUt2tcQtkn0BU365Vt3wUAtqfGam4QpZU35RXVhv6G]]></MediaId>
|
|
125
|
+
# <Format><![CDATA[amr]]></Format>
|
|
126
|
+
# <MsgId>5912592682802219078</MsgId>
|
|
127
|
+
# <Recognition><![CDATA[]]></Recognition>
|
|
128
|
+
# </xml>
|
|
129
|
+
class VoiceMessage < Message
|
|
130
|
+
|
|
131
|
+
def MediaId
|
|
132
|
+
@source.MediaId
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def Format
|
|
136
|
+
@source.Format
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# <xml>
|
|
141
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
142
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
143
|
+
# <CreateTime>1376632994</CreateTime>
|
|
144
|
+
# <MsgType><![CDATA[video]]></MsgType>
|
|
145
|
+
# <MediaId><![CDATA[TAAGb6iS5LcZR1d5ICiZTWGWi6-Upic9tlWDpAKcNJA]]></MediaId>
|
|
146
|
+
# <ThumbMediaId><![CDATA[U-xulPW4kq6KKMWFNaBSPc65Bcgr7Qopwex0DfCeyQs]]></ThumbMediaId>
|
|
147
|
+
# <MsgId>5912593687824566343</MsgId>
|
|
148
|
+
# </xml>
|
|
149
|
+
class VideoMessage < Message
|
|
150
|
+
|
|
151
|
+
def MediaId
|
|
152
|
+
@source.MediaId
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def ThumbMediaId
|
|
156
|
+
@source.ThumbMediaId
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
# ref: https://github.com/wolfg1969/rack-weixin/lib/weixin/model.rb
|
|
3
|
+
require 'roxml'
|
|
4
|
+
|
|
5
|
+
module WeixinRailsMiddleware
|
|
6
|
+
|
|
7
|
+
class ReplyMessage
|
|
8
|
+
include ROXML
|
|
9
|
+
xml_name :xml
|
|
10
|
+
#xml_convention :camelcase
|
|
11
|
+
|
|
12
|
+
xml_accessor :ToUserName, :cdata => true
|
|
13
|
+
xml_accessor :FromUserName, :cdata => true
|
|
14
|
+
xml_reader :CreateTime, :as => Integer
|
|
15
|
+
xml_reader :MsgType, :cdata => true
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@CreateTime = Time.now.to_i
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_xml
|
|
22
|
+
super.to_xml(:encoding => 'UTF-8', :indent => 0, :save_with => 0)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# <xml>
|
|
27
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
28
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
29
|
+
# <CreateTime>12345678</CreateTime>
|
|
30
|
+
# <MsgType><![CDATA[text]]></MsgType>
|
|
31
|
+
# <Content><![CDATA[Hello]]></Content>
|
|
32
|
+
# </xml>
|
|
33
|
+
|
|
34
|
+
class TextReplyMessage < ReplyMessage
|
|
35
|
+
xml_accessor :Content, :cdata => true
|
|
36
|
+
def initialize
|
|
37
|
+
super
|
|
38
|
+
@MsgType = 'text'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class Music
|
|
43
|
+
include ROXML
|
|
44
|
+
xml_accessor :Title, :cdata => true
|
|
45
|
+
xml_accessor :Description, :cdata => true
|
|
46
|
+
xml_accessor :MusicUrl, :cdata => true
|
|
47
|
+
xml_accessor :HQMusicUrl, :cdata => true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# <xml>
|
|
51
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
52
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
53
|
+
# <CreateTime>12345678</CreateTime>
|
|
54
|
+
# <MsgType><![CDATA[music]]></MsgType>
|
|
55
|
+
# <Music>
|
|
56
|
+
# <Title><![CDATA[TITLE]]></Title>
|
|
57
|
+
# <Description><![CDATA[DESCRIPTION]]></Description>
|
|
58
|
+
# <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
|
|
59
|
+
# <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
|
|
60
|
+
# <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>
|
|
61
|
+
# </Music>
|
|
62
|
+
# </xml>
|
|
63
|
+
|
|
64
|
+
class MusicReplyMessage < ReplyMessage
|
|
65
|
+
xml_accessor :Music, :as => Music
|
|
66
|
+
def initialize
|
|
67
|
+
super
|
|
68
|
+
@MsgType = 'music'
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class Article
|
|
73
|
+
include ROXML
|
|
74
|
+
xml_accessor :Title, :cdata => true
|
|
75
|
+
xml_accessor :Description, :cdata => true
|
|
76
|
+
xml_accessor :PicUrl, :cdata => true
|
|
77
|
+
xml_accessor :Url, :cdata => true
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# <xml>
|
|
81
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
82
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
83
|
+
# <CreateTime>12345678</CreateTime>
|
|
84
|
+
# <MsgType><![CDATA[news]]></MsgType>
|
|
85
|
+
# <ArticleCount>2</ArticleCount>
|
|
86
|
+
# <Articles>
|
|
87
|
+
# <item>
|
|
88
|
+
# <Title><![CDATA[title1]]></Title>
|
|
89
|
+
# <Description><![CDATA[description1]]></Description>
|
|
90
|
+
# <PicUrl><![CDATA[picurl]]></PicUrl>
|
|
91
|
+
# <Url><![CDATA[url]]></Url>
|
|
92
|
+
# </item>
|
|
93
|
+
# <item>
|
|
94
|
+
# <Title><![CDATA[title]]></Title>
|
|
95
|
+
# <Description><![CDATA[description]]></Description>
|
|
96
|
+
# <PicUrl><![CDATA[picurl]]></PicUrl>
|
|
97
|
+
# <Url><![CDATA[url]]></Url>
|
|
98
|
+
# </item>
|
|
99
|
+
# </Articles>
|
|
100
|
+
# </xml>
|
|
101
|
+
|
|
102
|
+
class NewsReplyMessage < ReplyMessage
|
|
103
|
+
xml_accessor :ArticleCount, :as => Integer
|
|
104
|
+
xml_accessor :Articles, :as => [Article], :in => 'Articles', :from => 'item'
|
|
105
|
+
def initialize
|
|
106
|
+
super
|
|
107
|
+
@MsgType = 'news'
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# <xml>
|
|
112
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
113
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
114
|
+
# <CreateTime>12345678</CreateTime>
|
|
115
|
+
# <MsgType><![CDATA[video]]></MsgType>
|
|
116
|
+
# <Video>
|
|
117
|
+
# <MediaId><![CDATA[media_id]]></MediaId>
|
|
118
|
+
# <Title><![CDATA[title]]></Title>
|
|
119
|
+
# <Description><![CDATA[description]]></Description>
|
|
120
|
+
# </Video>
|
|
121
|
+
# </xml>
|
|
122
|
+
|
|
123
|
+
class Video
|
|
124
|
+
include ROXML
|
|
125
|
+
xml_accessor :MediaId, :cdata => true
|
|
126
|
+
xml_accessor :Description, :cdata => true
|
|
127
|
+
xml_accessor :Title, :cdata => true
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class VideoReplyMessage < ReplyMessage
|
|
131
|
+
xml_accessor :Video, :as => Video
|
|
132
|
+
def initialize
|
|
133
|
+
super
|
|
134
|
+
@MsgType = 'video'
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# <xml>
|
|
139
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
140
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
141
|
+
# <CreateTime>12345678</CreateTime>
|
|
142
|
+
# <MsgType><![CDATA[voice]]></MsgType>
|
|
143
|
+
# <Voice>
|
|
144
|
+
# <MediaId><![CDATA[media_id]]></MediaId>
|
|
145
|
+
# </Voice>
|
|
146
|
+
# </xml>
|
|
147
|
+
class Voice
|
|
148
|
+
include ROXML
|
|
149
|
+
xml_accessor :MediaId, :cdata => true
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
class VoiceReplyMessage < ReplyMessage
|
|
153
|
+
xml_accessor :Voice, :as => Voice
|
|
154
|
+
def initialize
|
|
155
|
+
super
|
|
156
|
+
@MsgType = 'voice'
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# <xml>
|
|
161
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
|
162
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
|
163
|
+
# <CreateTime>12345678</CreateTime>
|
|
164
|
+
# <MsgType><![CDATA[image]]></MsgType>
|
|
165
|
+
# <Image>
|
|
166
|
+
# <MediaId><![CDATA[media_id]]></MediaId>
|
|
167
|
+
# </Image>
|
|
168
|
+
# </xml>
|
|
169
|
+
|
|
170
|
+
class Image
|
|
171
|
+
include ROXML
|
|
172
|
+
xml_accessor :MediaId, :cdata => true
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
class ImageReplyMessage < ReplyMessage
|
|
176
|
+
xml_accessor :Image, :as => Image
|
|
177
|
+
def initialize
|
|
178
|
+
super
|
|
179
|
+
@MsgType = 'image'
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module WeixinRailsMiddleware
|
|
2
|
+
module WeixinMessageHelper
|
|
3
|
+
|
|
4
|
+
def reply_text_message(from, to, content)
|
|
5
|
+
message = TextReplyMessage.new
|
|
6
|
+
message.ToUserName = to
|
|
7
|
+
message.FromUserName = from
|
|
8
|
+
message.Content = content
|
|
9
|
+
message.to_xml
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def generate_music(title, desc, music_url, hq_music_url)
|
|
13
|
+
music = Music.new
|
|
14
|
+
music.Title = title
|
|
15
|
+
music.Description = desc
|
|
16
|
+
music.MusicUrl = music_url
|
|
17
|
+
music.HQMusicUrl = hq_music_url
|
|
18
|
+
music
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# music = generate_music
|
|
22
|
+
def reply_music_message(from, to, music)
|
|
23
|
+
message = MusicReplyMessage.new
|
|
24
|
+
message.ToUserName = to
|
|
25
|
+
message.FromUserName = from
|
|
26
|
+
message.Music = music
|
|
27
|
+
message.to_xml
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def generate_article(title, desc, pic_url, link_url)
|
|
31
|
+
item = Article.new
|
|
32
|
+
item.Title = title
|
|
33
|
+
item.Description = desc
|
|
34
|
+
item.PicUrl = pic_url
|
|
35
|
+
item.Url = link_url
|
|
36
|
+
item
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# articles = [generate_article]
|
|
40
|
+
def reply_news_message(from, to, articles)
|
|
41
|
+
message = NewsReplyMessage.new
|
|
42
|
+
message.ToUserName = to
|
|
43
|
+
message.FromUserName = from
|
|
44
|
+
message.Articles = articles
|
|
45
|
+
message.ArticleCount = articles.count
|
|
46
|
+
message.to_xml
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def generate_video(media_id, desc, title)
|
|
50
|
+
video = Video.new
|
|
51
|
+
video.MediaId = media_id
|
|
52
|
+
video.Description = desc
|
|
53
|
+
video.Title = title
|
|
54
|
+
vodeo
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def replay_video_message(video)
|
|
58
|
+
message = VideoReplyMessage.new
|
|
59
|
+
message.Video = video
|
|
60
|
+
message.to_xml
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def generate_voice(media_id)
|
|
64
|
+
voice = Voice.new
|
|
65
|
+
voice.MediaId = media_id
|
|
66
|
+
voice
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def reply_voice_message(voice)
|
|
70
|
+
message = VoiceReplyMessage.new
|
|
71
|
+
message.Voice = voice
|
|
72
|
+
message.to_xml
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def generate_image(media_id)
|
|
76
|
+
image = Image.new
|
|
77
|
+
image.MediaId = media_id
|
|
78
|
+
image
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def reply_imgage_message(image)
|
|
82
|
+
message = ImageReplyMessage.new
|
|
83
|
+
message.Image = image
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# take the weixin params
|
|
87
|
+
def current_weixin_params
|
|
88
|
+
request.body.read
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# return a message class with current_weixin_params
|
|
92
|
+
def current_weixin_message
|
|
93
|
+
Message.factory(current_weixin_params)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: weixin_rails_middleware
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- DylanDeng
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-01-27 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: railties
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - '>='
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.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.1'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: nokogiri
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '>='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 1.6.1
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '>='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 1.6.1
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rails
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - '>='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.1'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
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.7.9
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - '>='
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 1.7.9
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: multi_xml
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - '>='
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 0.5.2
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - '>='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 0.5.2
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: roxml
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - '>='
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - '>='
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
description: weixin_rails_middleware for integration weixin develop
|
|
98
|
+
email:
|
|
99
|
+
- dylan@beansmile.com
|
|
100
|
+
executables: []
|
|
101
|
+
extensions: []
|
|
102
|
+
extra_rdoc_files: []
|
|
103
|
+
files:
|
|
104
|
+
- app/controllers/weixin_rails_middleware/application_controller.rb
|
|
105
|
+
- app/controllers/weixin_rails_middleware/weixin_controller.rb
|
|
106
|
+
- config/routes.rb
|
|
107
|
+
- lib/generators/templates/initializer.rb
|
|
108
|
+
- lib/generators/templates/weixin_controller.rb
|
|
109
|
+
- lib/generators/weixin_rails_middleware/install_generator.rb
|
|
110
|
+
- lib/tasks/weixin_rails_middleware_tasks.rake
|
|
111
|
+
- lib/weixin_rails_middleware/configuration.rb
|
|
112
|
+
- lib/weixin_rails_middleware/engine.rb
|
|
113
|
+
- lib/weixin_rails_middleware/message.rb
|
|
114
|
+
- lib/weixin_rails_middleware/reply_message.rb
|
|
115
|
+
- lib/weixin_rails_middleware/version.rb
|
|
116
|
+
- lib/weixin_rails_middleware/weixin_message_helper.rb
|
|
117
|
+
- lib/weixin_rails_middleware.rb
|
|
118
|
+
- MIT-LICENSE
|
|
119
|
+
- Rakefile
|
|
120
|
+
homepage: http://github.com/lanrion/weixin_rails_middleware
|
|
121
|
+
licenses: []
|
|
122
|
+
metadata: {}
|
|
123
|
+
post_install_message:
|
|
124
|
+
rdoc_options: []
|
|
125
|
+
require_paths:
|
|
126
|
+
- lib
|
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - '>='
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
|
+
requirements:
|
|
134
|
+
- - '>='
|
|
135
|
+
- !ruby/object:Gem::Version
|
|
136
|
+
version: '0'
|
|
137
|
+
requirements: []
|
|
138
|
+
rubyforge_project:
|
|
139
|
+
rubygems_version: 2.0.3
|
|
140
|
+
signing_key:
|
|
141
|
+
specification_version: 4
|
|
142
|
+
summary: weixin_rails_middleware for integration weixin
|
|
143
|
+
test_files: []
|