sinatra-weixin-robot 0.0.1

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.
@@ -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: []