sinatra-weixin-robot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ module Sinatra
2
+ module WeiXinRobot
3
+ VERSION = '0.0.1' unless const_defined? :VERSION
4
+ def self.version
5
+ "Sinatra::WeiXinRobot v#{VERSION}"
6
+ end
7
+ end # WeiXinRobot
8
+ end # Sinatra
9
+
10
+ require 'sinatra/weixin-robot'
@@ -0,0 +1,195 @@
1
+ # encoding: utf-8
2
+
3
+ require 'sinatra/base'
4
+ require 'digest/sha1'
5
+
6
+ module Sinatra
7
+ module WeiXinRobot
8
+ module RobotHelpers
9
+ def generate_signature(token=nil)
10
+ weixin_token = settings.wexin_token || token
11
+ signature, timestamp, nonce = params[:signature], params[:timestamp], params[:nonce]
12
+ weixin_sha1 = [token, timestamp.to_s, nonce.to_s].sort!.join
13
+ Digest::SHA1.hexdigest(weixin_sha1)
14
+ end
15
+
16
+ def message_receiver(msg)
17
+ Sinatra::WeiXinRobot::Receiver.message(msg)
18
+ end
19
+ end
20
+ module MessageHelpers
21
+ def text?
22
+ @msg_type == "text"
23
+ end
24
+
25
+ def music?
26
+ @msg_type == "music"
27
+ end
28
+
29
+ def news?
30
+ @msg_type == "news"
31
+ end
32
+
33
+ def image?
34
+ @msg_type == "image"
35
+ end
36
+ def location?
37
+ @msg_type == "location"
38
+ end
39
+ def link?
40
+ @msg_type == "link"
41
+ end
42
+
43
+ def event?
44
+ @msg_type == "event"
45
+ end
46
+ end
47
+ class Receiver
48
+ include MessageHelpers
49
+ attr_reader :robot, :user,
50
+ :create_time,
51
+ :raw_meesage,
52
+ :content,
53
+ :pic_url,
54
+ :title, :description, :url,
55
+ :location_y, :location_x, :scale, :label,
56
+ :event, :latitude, :precision, :foobar
57
+ def initialize(raw_message)
58
+ if raw_message.instance_of?(StringIO)
59
+ @raw_message = raw_message.string
60
+ elsif raw_message.instance_of?(Tempfile)
61
+ @raw_message = raw_message.read
62
+ else
63
+ @raw_message = raw_message.to_str
64
+ end
65
+ @robot = @raw_message.scan(/<ToUserName><!\[CDATA\[(.*)\]\]><\/ToUserName>/).flatten.join
66
+ @user = @raw_message.scan(/<FromUserName><!\[CDATA\[(.*)\]\]><\/FromUserName>/).flatten.join
67
+ @create_time = @raw_message.scan(/<CreateTime>(\d+)<\/CreateTime>/).flatten.join
68
+ @msg_type = @raw_message.scan(/<MsgType><!\[CDATA\[(.*)\]\]><\/MsgType>/).flatten.join
69
+ @msg_id = @raw_message.scan(/<MsgId>(\d+)<\/MsgId>/).flatten.join
70
+ end
71
+ def self.message(raw_message)
72
+ msg = new(raw_message)
73
+ msg.handler
74
+ msg
75
+ end
76
+ def handler
77
+ if text?
78
+ @content = @raw_message.scan(/<Content><!\[CDATA\[(.*)\]\]><\/Content>/).flatten.join
79
+ elsif image?
80
+ @pic_url = @raw_message.scan(/<PicUrl><!\[CDATA\[(.*)\]><\/PicUrl>/).flatten.join
81
+ elsif location?
82
+ @location_x = @raw_message.scan(/<Location_X>(.*)<\/Location_X>/).flatten.join
83
+ @location_y = @raw_message.scan(/<Location_Y>(.*)<\/Location_Y>/).flatten.join
84
+ @scale = @raw_message.scan(/<Scale>(\d+)<\/Scale>/).flatten.join
85
+ @label = @raw_message.scan(/<Label><!\[CDATA\[(.*)\]\]><\/Label>/).flatten.join
86
+ elsif link?
87
+ @title = @raw_message.scan(/<Title><!\[CDATA\[(.*)\]\]><\/Title>/).flatten.join
88
+ @description = @raw_message.scan(/<Description><!\[CDATA\[(.*)\]\]><\/Description>/).flatten.join
89
+ @url = @raw_message.scan(/<Url><!\[CDATA\[(.*)\]\]><\/Url>/).flatten.join
90
+ elsif event?
91
+ @event = @raw_message.scan(/<Event><!\[CDATA\[(.*)\]\]><\/Event>/).flatten.join
92
+ @latitude = @raw_message.scan(/<Latitude>(.*)<\/Latitude>/).flatten.join
93
+ @precision = @raw_message.scan(/<Precision>(.*)<\/Precision>/).flatten.join
94
+ else
95
+ raise TypeError
96
+ end
97
+ end
98
+
99
+ def sender(params={}, &block)
100
+ options = {:robot => @robot, :user => @user, :msg_type => "text"}.merge!(params)
101
+ if block_given?
102
+ block.call(Reply.new(options))
103
+ end
104
+ end
105
+ end # Receiver
106
+ class Reply
107
+ include MessageHelpers
108
+ attr_accessor :content,
109
+ :create_time,
110
+ :msg_type,
111
+ :func_flag,
112
+ :music,
113
+ :articles
114
+
115
+ attr_reader :user, :robot
116
+ def initialize(options={})
117
+ @user = options.delete(:user)
118
+ @robot = options.delete(:robot)
119
+ @create_time = options.delete(:create_time) || Time.now.to_i
120
+ @msg_type = options.delete(:msg_type)
121
+ @func_flag = options.delete(:func_flag) || 0
122
+ @content = options.delete(:content)
123
+ @articles = options.delete(:articles) || []
124
+ @music = options.delete(:music)
125
+ end
126
+
127
+ def articles=(hash)
128
+ @articles.push(hash)
129
+ end
130
+
131
+ def text_message
132
+ raise RuntimeError, "#{__LINE__} `@content` not defined" if @content.nil?
133
+ "<Content><![CDATA[#{@content}]]></Content>"
134
+ end
135
+
136
+ def music_message
137
+ raise RuntimeError, "#{__LINE__} `@music` not defined" if @music.nil?
138
+ xml = "<Music>"
139
+ xml += "<Title><![CDATA[#{@music[:title]}]]></Title>"
140
+ xml += "<Description><![CDATA[#{@music[:description]}]]></Description>"
141
+ xml += "<MusicUrl><![CDATA[#{@music[:url]}]]></MusicUrl>\n"
142
+ xml += "<HQMusicUrl><![CDATA[#{@music[:hq_url]}]]></HQMusicUrl>"
143
+ xml += "</Music>"
144
+ end
145
+
146
+ def news_message
147
+ raise RuntimeError, "#{__LINE__} `@news` not defined" if @articles.nil?
148
+ xml = "<ArticleCount>#{@articles.length}</ArticleCount>"
149
+ xml += "<Articles>"
150
+ @articles.each do |artcile|
151
+ xml += "<item>"
152
+ xml += "<Title><![CDATA[#{artcile[:title]}]]></Title>"
153
+ xml += "<Description><![CDATA[#{artcile[:description]}]]></Description>"
154
+ xml += "<PicUrl><![CDATA[#{artcile[:pic_url]}]]></PicUrl>"
155
+ xml += "<Url><![CDATA[#{artcile[:url]}]]></Url>"
156
+ xml += "</item>"
157
+ end
158
+ xml += "</Articles>"
159
+ end
160
+
161
+ def to_xml
162
+ xml = "<xml>"
163
+ xml += "<ToUserName><![CDATA[#{@user}]]></ToUserName>"
164
+ xml += "<FromUserName><![CDATA[#{@robot}]]></FromUserName>"
165
+ xml += "<CreateTime>#{@create_time}</CreateTime>"
166
+ xml += "<MsgType><![CDATA[#{@msg_type}]]></MsgType>"
167
+ xml += text_message if text?
168
+ xml += music_message if music?
169
+ xml += news_message if news?
170
+ xml += "<FuncFlag>#{@func_flag}</FuncFlag>"
171
+ xml += "</xml>"
172
+ end
173
+
174
+ def complete!
175
+ to_xml
176
+ self
177
+ end
178
+ end
179
+ def self.registered(robot)
180
+ robot.set :weixin_token, "your-token"
181
+ robot.set :weixin_uri, "http://wwww.your-weixin-bot-url.com/"
182
+ robot.set :weixin_path, URI(robot.settings.weixin_uri).path.to_s
183
+ robot.helpers RobotHelpers
184
+ robot.before "#{robot.settings.weixin_path}" do
185
+ if request.request_method == "POST"
186
+ content_type 'application/xml'
187
+ end
188
+ end
189
+ end
190
+ end # WeiXinRobot
191
+ register WeiXinRobot
192
+ end # Sinatra
193
+
194
+
195
+
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-weixin-robot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - KennX
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-18 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: WeiXin Robot for sinatra
15
+ email:
16
+ - kennx9@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/sinatra/weixin-robot.rb
22
+ - lib/sinatra-weixin-robot.rb
23
+ homepage: https://github.com/kennx/weixin_robot
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: 1.9.2
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.25
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: WeiXin Robot for sinatra
47
+ test_files: []