weixin_rails_middleware_uxinji 1.0.4

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: a4f8e4584fbb40a0097d749f8e08b626f10db4cd
4
+ data.tar.gz: d68d4a280935b7796f600b9188b70edbe543989e
5
+ SHA512:
6
+ metadata.gz: ada7e9e76c2adc0ddd1882d233caff70dd83b1c987bb652aceb365860c00d730ec9ffa0f765b861c90559a9fcf80e9ac44b049b6794feea4abb4925e28fa3943
7
+ data.tar.gz: beea4453004e0884e67b6c31d2777f60e0b56d605606da3c72e8c1379f9a9a0c7cb9316bd4fe70a4169a5cf7380c2070d1d1c0207cfdb6a6f4a7bba9b3e4173a
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/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # WeixinRailsMiddleware
2
+
3
+ This project rocks and uses MIT-LICENSE.
4
+
5
+ https://rubygems.org/gems/weixin_rails_middleware
6
+
7
+ Example: https://github.com/lanrion/weixin_rails_middleware_example
8
+
9
+ ## Function
10
+
11
+ * 自动验证微信请求。
12
+
13
+ * 无需拼接XML格式,只需要使用 `WeixinMessageHelper` 辅助方法,即可快速回复。
14
+ 使用方法: ` render xml: reply_text_message("Your Message: #{current_message.Content}") `
15
+
16
+ * 支持自定义token,适合一个用户使用。
17
+
18
+ * 支持多用户token: 适合多用户注册网站,每个用户有不同的token,通过 `weixin_rails_middleware.rb` 配置好存储token的Model与字段名,即可。
19
+
20
+ * 文本回复: `reply_text_message(content)`。
21
+
22
+ * 音乐回复: `reply_music_message(music)`, `generate_music(title, desc, music_url, hq_music_url)`。
23
+
24
+ * 图文回复: `reply_news_message(articles)`, `generate_article(title, desc, pic_url, link_url)`。
25
+
26
+ * 视频回复: `replay_video_message(video)`。
27
+
28
+ * 语音回复: `reply_voice_message(voice)`。
29
+
30
+ * 图片回复: `reply_imgage_message(image)`。
31
+
32
+ * 地理位置回复: 自定义需求。
33
+
34
+ ## Install
35
+
36
+ In your `Gemfile`: `gem 'weixin_rails_middleware'`
37
+
38
+ And `bundle intall`
39
+
40
+ ## Init weixin_rails_middleware
41
+
42
+ `rails generate weixin_rails_middleware:install`
43
+
44
+ It will create `config/initializers/weixin_rails_middleware.rb`
45
+
46
+ Note: You need to checkout comments in file
47
+
48
+ And
49
+
50
+ Create `app/decorators/controllers/weixin_rails_middleware/weixin_controller_decorator.rb`
51
+
52
+ Note: You need to overwrite the `reply` method. And there are two instance: `@weixin_message`,
53
+ `@weixin_public_account(token_model instance if you setup, otherwise return nil)`
54
+
55
+ Other
56
+
57
+ Add a line: `WeixinRailsMiddleware::Engine, at: WeixinRailsMiddleware.config.engine_path` in `routes.rb`
58
+
59
+ ## Helpers
60
+
61
+ Please see detail in `weixin_message_helper.rb`
62
+
63
+ ## How to test
64
+ Install `ngrok` and run with `ngrok 4000`, `4000` is your port that Rails Server needed
65
+
66
+ Then, it will generate like this:
67
+
68
+ ```
69
+ Tunnel Status online
70
+ Version 1.6/1.5
71
+ Forwarding http://e0ede89.ngrok.com -> 127.0.0.1:4000
72
+ Forwarding https://e0ede89.ngrok.com -> 127.0.0.1:4000
73
+ Web Interface 127.0.0.1:4040
74
+ # Conn 67
75
+ Avg Conn Time 839.50ms
76
+
77
+ ```
78
+
79
+ Yes, She is `http://e0ede89.ngrok.com`
80
+
81
+ 神器!!
82
+
83
+ ## XML parser
84
+ We use `roxml` to generate XML and use `multi_xml` to parse `XML`, but we let them all use `nokogiri` plugin default.
85
+
86
+ ## TODO
87
+
88
+ * 添加微信自定义菜单
89
+ * 多媒体资料上传
90
+
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,4 @@
1
+ module WeixinRailsMiddleware
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,96 @@
1
+ module WeixinRailsMiddleware
2
+ class WeixinController < ApplicationController
3
+ include WeixinMessageHelper
4
+
5
+ skip_before_filter :verify_authenticity_token
6
+ before_action :check_weixin_params, only: [:index, :reply]
7
+ before_action :set_weixin_public_account, :set_weixin_message, only: :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
+ unless 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
+ token_string.present? ? check_token_string : check_token_model_instance
29
+ end
30
+
31
+ def token_string
32
+ WeixinRailsMiddleware.config.token_string
33
+ end
34
+
35
+ def check_token_string
36
+ if current_weixin_token != token_string
37
+ render text: "Forbidden", status: 403
38
+ return false
39
+ end
40
+ true
41
+ end
42
+
43
+ def check_token_model_instance
44
+ if token_model_instance.blank?
45
+ render text: "Forbidden", status: 403
46
+ return false
47
+ end
48
+ true
49
+ end
50
+
51
+ def is_hexdigest?
52
+ temp_array = weixin_token, timestamp, nonce
53
+ current_signature = Digest::SHA1.hexdigest(temp_array.sort.join)
54
+ return true if current_signature == signature
55
+ false
56
+ end
57
+
58
+ [:signature, :timestamp, :nonce, :weixin_token].each do |e|
59
+ define_method e do
60
+ params[e]
61
+ end
62
+ end
63
+
64
+ def current_weixin_token
65
+ @current_weixin_token ||= weixin_token
66
+ end
67
+
68
+ def token_model_instance
69
+ token_model = WeixinRailsMiddleware.config.token_model_class
70
+ token_column = WeixinRailsMiddleware.config.token_column
71
+ token_model_instance = token_model.where("#{token_column}" => current_weixin_token).first
72
+ end
73
+
74
+ # e.g. will generate +@weixin_public_account+
75
+ def set_weixin_public_account
76
+ return nil if token_string.present?
77
+ @weixin_public_account ||= token_model_instance
78
+ end
79
+
80
+ def set_weixin_message
81
+ # Get the current_message
82
+ @weixin_message ||= current_weixin_message
83
+ end
84
+
85
+ # take the weixin params
86
+ def current_weixin_params
87
+ @current_weixin_params ||= request.body.read
88
+ end
89
+
90
+ # return a message class with current_weixin_params
91
+ def current_weixin_message
92
+ Message.factory(current_weixin_params)
93
+ end
94
+
95
+ end
96
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ WeixinRailsMiddleware::Engine.routes.draw do
2
+ get 'weixin/:weixin_token', to: 'weixin#index'
3
+ post 'weixin/:weixin_token', to: 'weixin#reply'
4
+ end
@@ -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,39 @@
1
+ WeixinRailsMiddleware::WeixinController.class_eval do
2
+
3
+ # There are two instance: @weixin_message,
4
+ # @weixin_public_account(token_model instance if you setup, otherwise return nil)
5
+ def reply
6
+ render xml: send("response_#{@weixin_message.MsgType}_message", {})
7
+ end
8
+
9
+ private
10
+
11
+ def response_text_message(options={})
12
+ reply_text_message("Your Message: #{@weixin_message.Content}")
13
+
14
+ end
15
+
16
+ def response_location_message(options={})
17
+ reply_text_message("Your Location: #{@weixin_message.Location_X}, #{@weixin_message.Location_Y}")
18
+ end
19
+
20
+ def response_image_message(options={})
21
+ # image message handler
22
+ end
23
+
24
+ def response_link_message(options={})
25
+ # link message handler
26
+ end
27
+
28
+ def response_event_message(options={})
29
+ # event messge handler
30
+ end
31
+
32
+ def response_voice_message(options={})
33
+ # voice message handler
34
+ end
35
+
36
+ def response_video_message(options={})
37
+ # video message handler
38
+ end
39
+ 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,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :weixin_rails_middleware do
3
+ # # Task goes here
4
+ # 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 = "/".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,5 @@
1
+ module WeixinRailsMiddleware
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace WeixinRailsMiddleware
4
+ end
5
+ end
@@ -0,0 +1,163 @@
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
+ # multi_xml will use Nokogiri if it is available
8
+ MultiXml.parser = :nokogiri
9
+
10
+ module WeixinRailsMiddleware
11
+
12
+ class Message
13
+
14
+ def initialize(hash)
15
+ @source = OpenStruct.new(hash)
16
+ end
17
+
18
+ def method_missing(method, *args, &block)
19
+ @source.send(method, *args, &block)
20
+ end
21
+
22
+ def CreateTime
23
+ @source.CreateTime.to_i
24
+ end
25
+
26
+ def MsgId
27
+ @source.MsgId.to_i
28
+ end
29
+
30
+ def self.factory(xml)
31
+ hash = MultiXml.parse(xml)['xml']
32
+ case hash['MsgType']
33
+ when 'text'
34
+ TextMessage.new(hash)
35
+ when 'image'
36
+ ImageMessage.new(hash)
37
+ when 'location'
38
+ LocationMessage.new(hash)
39
+ when 'link'
40
+ LinkMessage.new(hash)
41
+ when 'event'
42
+ EventMessage.new(hash)
43
+ when 'voice'
44
+ VoiceMessage.new(hash)
45
+ when 'video'
46
+ VideoMessage.new(hash)
47
+ else
48
+ raise ArgumentError, 'Unknown Message'
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ # <xml>
55
+ # <ToUserName><![CDATA[toUser]]></ToUserName>
56
+ # <FromUserName><![CDATA[fromUser]]></FromUserName>
57
+ # <CreateTime>1348831860</CreateTime>
58
+ # <MsgType><![CDATA[text]]></MsgType>
59
+ # <Content><![CDATA[this is a test]]></Content>
60
+ # <MsgId>1234567890123456</MsgId>
61
+ # </xml>
62
+ TextMessage = Class.new(Message)
63
+
64
+ # <xml>
65
+ # <ToUserName><![CDATA[toUser]]></ToUserName>
66
+ # <FromUserName><![CDATA[fromUser]]></FromUserName>
67
+ # <CreateTime>1348831860</CreateTime>
68
+ # <MsgType><![CDATA[image]]></MsgType>
69
+ # <PicUrl><![CDATA[this is a url]]></PicUrl>
70
+ # <MsgId>1234567890123456</MsgId>
71
+ # </xml>
72
+ ImageMessage = Class.new(Message)
73
+
74
+ # <xml>
75
+ # <ToUserName><![CDATA[toUser]]></ToUserName>
76
+ # <FromUserName><![CDATA[fromUser]]></FromUserName>
77
+ # <CreateTime>1351776360</CreateTime>
78
+ # <MsgType><![CDATA[link]]></MsgType>
79
+ # <Title><![CDATA[公众平台官网链接]]></Title>
80
+ # <Description><![CDATA[公众平台官网链接]]></Description>
81
+ # <Url><![CDATA[url]]></Url>
82
+ # <MsgId>1234567890123456</MsgId>
83
+ # </xml>
84
+ LinkMessage = Class.new(Message)
85
+
86
+ # <xml>
87
+ # <ToUserName><![CDATA[toUser]]></ToUserName>
88
+ # <FromUserName><![CDATA[FromUser]]></FromUserName>
89
+ # <CreateTime>123456789</CreateTime>
90
+ # <MsgType><![CDATA[event]]></MsgType>
91
+ # <Event><![CDATA[EVENT]]></Event>
92
+ # <EventKey><![CDATA[EVENTKEY]]></EventKey>
93
+ # </xml>
94
+ EventMessage = Class.new(Message)
95
+
96
+ # <xml>
97
+ # <ToUserName><![CDATA[toUser]]></ToUserName>
98
+ # <FromUserName><![CDATA[fromUser]]></FromUserName>
99
+ # <CreateTime>1351776360</CreateTime>
100
+ # <MsgType><![CDATA[location]]></MsgType>
101
+ # <Location_X>23.134521</Location_X>
102
+ # <Location_Y>113.358803</Location_Y>
103
+ # <Scale>20</Scale>
104
+ # <Label><![CDATA[位置信息]]></Label>
105
+ # <MsgId>1234567890123456</MsgId>
106
+ # </xml>
107
+ class LocationMessage < Message
108
+
109
+ def Location_X
110
+ @source.Location_X.to_f
111
+ end
112
+
113
+ def Location_Y
114
+ @source.Location_Y.to_f
115
+ end
116
+
117
+ def Scale
118
+ @source.Scale.to_i
119
+ end
120
+ end
121
+
122
+ # <xml>
123
+ # <ToUserName><![CDATA[toUser]]></ToUserName>
124
+ # <FromUserName><![CDATA[fromUser]]></FromUserName>
125
+ # <CreateTime>1376632760</CreateTime>
126
+ # <MsgType><![CDATA[voice]]></MsgType>
127
+ # <MediaId><![CDATA[Qyb0tgux6QLjhL6ipvFZJ-kUt2tcQtkn0BU365Vt3wUAtqfGam4QpZU35RXVhv6G]]></MediaId>
128
+ # <Format><![CDATA[amr]]></Format>
129
+ # <MsgId>5912592682802219078</MsgId>
130
+ # <Recognition><![CDATA[]]></Recognition>
131
+ # </xml>
132
+ class VoiceMessage < Message
133
+
134
+ def MediaId
135
+ @source.MediaId
136
+ end
137
+
138
+ def Format
139
+ @source.Format
140
+ end
141
+ end
142
+
143
+ # <xml>
144
+ # <ToUserName><![CDATA[toUser]]></ToUserName>
145
+ # <FromUserName><![CDATA[fromUser]]></FromUserName>
146
+ # <CreateTime>1376632994</CreateTime>
147
+ # <MsgType><![CDATA[video]]></MsgType>
148
+ # <MediaId><![CDATA[TAAGb6iS5LcZR1d5ICiZTWGWi6-Upic9tlWDpAKcNJA]]></MediaId>
149
+ # <ThumbMediaId><![CDATA[U-xulPW4kq6KKMWFNaBSPc65Bcgr7Qopwex0DfCeyQs]]></ThumbMediaId>
150
+ # <MsgId>5912593687824566343</MsgId>
151
+ # </xml>
152
+ class VideoMessage < Message
153
+
154
+ def MediaId
155
+ @source.MediaId
156
+ end
157
+
158
+ def ThumbMediaId
159
+ @source.ThumbMediaId
160
+ end
161
+ end
162
+
163
+ 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,3 @@
1
+ module WeixinRailsMiddleware
2
+ VERSION = "1.0.4"
3
+ end
@@ -0,0 +1,97 @@
1
+ module WeixinRailsMiddleware
2
+ module WeixinMessageHelper
3
+
4
+ # e.g.
5
+ # reply_text_message(@weixin_message.ToUserName, @weixin_message.FromUserName, "Your Message: #{@weixin_message.Content}")
6
+ # Or reply_text_message("Your Message: #{@weixin_message.Content}")
7
+ def reply_text_message(from=nil, to=nil, content)
8
+ message = TextReplyMessage.new
9
+ message.FromUserName = from || @weixin_message.ToUserName
10
+ message.ToUserName = to || @weixin_message.FromUserName
11
+ message.Content = content
12
+ message.to_xml
13
+ end
14
+
15
+ def generate_music(title, desc, music_url, hq_music_url)
16
+ music = Music.new
17
+ music.Title = title
18
+ music.Description = desc
19
+ music.MusicUrl = music_url
20
+ music.HQMusicUrl = hq_music_url
21
+ music
22
+ end
23
+
24
+ # music = generate_music
25
+ def reply_music_message(from=nil, to=nil, music)
26
+ message = MusicReplyMessage.new
27
+ message.FromUserName = from || @weixin_message.ToUserName
28
+ message.ToUserName = to || @weixin_message.FromUserName
29
+ message.Music = music
30
+ message.to_xml
31
+ end
32
+
33
+ def generate_article(title, desc, pic_url, link_url)
34
+ item = Article.new
35
+ item.Title = title
36
+ item.Description = desc
37
+ item.PicUrl = pic_url
38
+ item.Url = link_url
39
+ item
40
+ end
41
+
42
+ # articles = [generate_article]
43
+ def reply_news_message(from=nil, to=nil, articles)
44
+ message = NewsReplyMessage.new
45
+ message.FromUserName = from || @weixin_message.ToUserName
46
+ message.ToUserName = to || @weixin_message.FromUserName
47
+ message.Articles = articles
48
+ message.ArticleCount = articles.count
49
+ message.to_xml
50
+ end
51
+
52
+ def generate_video(media_id, desc, title)
53
+ video = Video.new
54
+ video.MediaId = media_id
55
+ video.Description = desc
56
+ video.Title = title
57
+ vodeo
58
+ end
59
+
60
+ def replay_video_message(from=nil, to=nil, video)
61
+ message = VideoReplyMessage.new
62
+ message.FromUserName = from || @weixin_message.ToUserName
63
+ message.ToUserName = to || @weixin_message.FromUserName
64
+ message.Video = video
65
+ message.to_xml
66
+ end
67
+
68
+ def generate_voice(media_id)
69
+ voice = Voice.new
70
+ voice.MediaId = media_id
71
+ voice
72
+ end
73
+
74
+ def reply_voice_message(from=nil, to=nil, voice)
75
+ message = VoiceReplyMessage.new
76
+ message.FromUserName = from || @weixin_message.ToUserName
77
+ message.ToUserName = to || @weixin_message.FromUserName
78
+ message.Voice = voice
79
+ message.to_xml
80
+ end
81
+
82
+ def generate_image(media_id)
83
+ image = Image.new
84
+ image.MediaId = media_id
85
+ image
86
+ end
87
+
88
+ def reply_imgage_message(from=nil, to=nil, image)
89
+ message = ImageReplyMessage.new
90
+ message.FromUserName = from || @weixin_message.ToUserName
91
+ message.ToUserName = to || @weixin_message.FromUserName
92
+ message.Image = image
93
+ message.to_xml
94
+ end
95
+
96
+ end
97
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: weixin_rails_middleware_uxinji
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ platform: ruby
6
+ authors:
7
+ - lanrion
8
+ - turristan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-02-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '3.1'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '3.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: nokogiri
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: 1.6.1
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: 1.6.1
42
+ - !ruby/object:Gem::Dependency
43
+ name: rails
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '3.1'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '3.1'
56
+ - !ruby/object:Gem::Dependency
57
+ name: multi_json
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: 1.7.9
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 1.7.9
70
+ - !ruby/object:Gem::Dependency
71
+ name: multi_xml
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 0.5.2
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: 0.5.2
84
+ - !ruby/object:Gem::Dependency
85
+ name: roxml
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: 3.3.1
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: 3.3.1
98
+ - !ruby/object:Gem::Dependency
99
+ name: rest_client
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: 1.6.7
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: 1.6.7
112
+ description: weixin_rails_middleware for uxinji weixin public service
113
+ email:
114
+ - huaitao-deng@foxmail.com
115
+ - turristan@gmail.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - MIT-LICENSE
121
+ - README.md
122
+ - Rakefile
123
+ - app/controllers/weixin_rails_middleware/application_controller.rb
124
+ - app/controllers/weixin_rails_middleware/weixin_controller.rb
125
+ - config/routes.rb
126
+ - lib/generators/templates/initializer.rb
127
+ - lib/generators/templates/weixin_controller.rb
128
+ - lib/generators/weixin_rails_middleware/install_generator.rb
129
+ - lib/tasks/weixin_rails_middleware_tasks.rake
130
+ - lib/weixin_rails_middleware.rb
131
+ - lib/weixin_rails_middleware/configuration.rb
132
+ - lib/weixin_rails_middleware/engine.rb
133
+ - lib/weixin_rails_middleware/message.rb
134
+ - lib/weixin_rails_middleware/reply_message.rb
135
+ - lib/weixin_rails_middleware/version.rb
136
+ - lib/weixin_rails_middleware/weixin_message_helper.rb
137
+ homepage: https://github.com/turristan/weixin_rails_middleware/tree/uxinji
138
+ licenses: []
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.2.2
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: weixin_rails_middleware specified uxinji
160
+ test_files: []