mp_weixin 0.1.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.
Files changed (52) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +7 -0
  4. data/.travis.yml +20 -0
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +308 -0
  9. data/Rakefile +31 -0
  10. data/lib/config/mp_weixin_error.yml +82 -0
  11. data/lib/mp_weixin.rb +59 -0
  12. data/lib/mp_weixin/access_token.rb +172 -0
  13. data/lib/mp_weixin/client.rb +199 -0
  14. data/lib/mp_weixin/config.rb +36 -0
  15. data/lib/mp_weixin/error.rb +27 -0
  16. data/lib/mp_weixin/interface/base.rb +43 -0
  17. data/lib/mp_weixin/interface/group.rb +92 -0
  18. data/lib/mp_weixin/interface/menu.rb +73 -0
  19. data/lib/mp_weixin/interface/message.rb +38 -0
  20. data/lib/mp_weixin/interface/promotion.rb +48 -0
  21. data/lib/mp_weixin/interface/user.rb +39 -0
  22. data/lib/mp_weixin/models/event.rb +123 -0
  23. data/lib/mp_weixin/models/message.rb +227 -0
  24. data/lib/mp_weixin/models/reply_message.rb +180 -0
  25. data/lib/mp_weixin/response.rb +93 -0
  26. data/lib/mp_weixin/response_rule.rb +46 -0
  27. data/lib/mp_weixin/server.rb +39 -0
  28. data/lib/mp_weixin/server_helper.rb +94 -0
  29. data/lib/mp_weixin/version.rb +3 -0
  30. data/lib/support/active_model.rb +3 -0
  31. data/lib/support/active_model/model.rb +99 -0
  32. data/mp_weixin.gemspec +44 -0
  33. data/spec/client_spec.rb +87 -0
  34. data/spec/mp_weixin/access_token_spec.rb +140 -0
  35. data/spec/mp_weixin/client_spec.rb +111 -0
  36. data/spec/mp_weixin/config_spec.rb +24 -0
  37. data/spec/mp_weixin/interface/base_spec.rb +16 -0
  38. data/spec/mp_weixin/interface/group_spec.rb +133 -0
  39. data/spec/mp_weixin/interface/menu_spec.rb +72 -0
  40. data/spec/mp_weixin/interface/message_spec.rb +36 -0
  41. data/spec/mp_weixin/interface/promotion_spec.rb +48 -0
  42. data/spec/mp_weixin/interface/user_spec.rb +76 -0
  43. data/spec/mp_weixin/models/event_spec.rb +94 -0
  44. data/spec/mp_weixin/models/message_spec.rb +300 -0
  45. data/spec/mp_weixin/models/reply_message_spec.rb +365 -0
  46. data/spec/mp_weixin/server_helper_spec.rb +165 -0
  47. data/spec/mp_weixin/server_spec.rb +56 -0
  48. data/spec/spec_helper.rb +51 -0
  49. data/spec/support/mp_weixin.rb +7 -0
  50. data/spec/support/rspec_mixin.rb +8 -0
  51. data/spec/support/weixin.yml +12 -0
  52. metadata +363 -0
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe MpWeixin::Interface::User do
5
+ let(:access_token) { 'ACCESS_TOKEN' }
6
+ let(:token_hash) { {"expires_in" => "7200", "access_token" => access_token} }
7
+ let(:openid) { "o6_bmjrPTlm6_2sgVt7hMZOPfL2M" }
8
+ let(:info_json) {
9
+ MultiJson.encode({
10
+ openid: openid
11
+ })
12
+ }
13
+
14
+ let (:sucess_info) {
15
+ MultiJson.encode({
16
+ subscribe: 1,
17
+ openid: openid,
18
+ nickname: "Band",
19
+ sex: 1,
20
+ language: "zh_CN",
21
+ city: "广州",
22
+ province: "广东",
23
+ country: "中国",
24
+ headimgurl: "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
25
+ subscribe_time: 1382694957
26
+ })
27
+ }
28
+ let(:get_users_json) {
29
+ MultiJson.encode({
30
+ openid: openid
31
+ })
32
+ }
33
+ let(:sucess_get_users) {
34
+ MultiJson.encode({
35
+ total: 2,
36
+ count: 2,
37
+ data: {
38
+ openid:
39
+ ["","OPENID1","OPENID2"]
40
+ },
41
+ next_openid: "NEXT_OPENID"
42
+ })
43
+ }
44
+ let(:client) {
45
+ MpWeixin::Client.from_hash(token_hash) do |builder|
46
+ builder.request :url_encoded
47
+ builder.adapter :test do |stub|
48
+ stub.send(:get, "/cgi-bin/user/info") {|env|
49
+ if env[:params].values.include?(openid)
50
+ [200, {'Content-Type' => 'application/json'}, sucess_info]
51
+ end
52
+ }
53
+ stub.send(:get, "/cgi-bin/user/get") {|env|
54
+ if env[:params].values.include?(openid)
55
+ [200, {'Content-Type' => 'application/json'}, sucess_get_users]
56
+ end
57
+ }
58
+ end
59
+ end
60
+ }
61
+
62
+ context "#menu" do
63
+
64
+ subject { MpWeixin::Interface::User.new(client) }
65
+
66
+ it "info info_hash with sucess_info return" do
67
+ info_hash = JSON.parse info_json
68
+ expect(subject.info(info_hash).body).to eq(sucess_info)
69
+ end
70
+
71
+ it "get_users get_users_hash with sucess_get_users return" do
72
+ get_users_hash = JSON.parse get_users_json
73
+ expect(subject.get_users(get_users_hash).body).to eq(sucess_get_users)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe MpWeixin::Event do
6
+
7
+ let(:subscribe_event_xml) {
8
+ %(
9
+ <xml>
10
+ <ToUserName><![CDATA[toUser]]></ToUserName>
11
+ <FromUserName><![CDATA[FromUser]]></FromUserName>
12
+ <CreateTime>123456789</CreateTime>
13
+ <MsgType><![CDATA[event]]></MsgType>
14
+ <Event><![CDATA[subscribe]]></Event>
15
+ </xml>
16
+ )
17
+ }
18
+
19
+ let(:location_event_xml) {
20
+ %(
21
+ <xml>
22
+ <ToUserName><![CDATA[toUser]]></ToUserName>
23
+ <FromUserName><![CDATA[fromUser]]></FromUserName>
24
+ <CreateTime>123456789</CreateTime>
25
+ <MsgType><![CDATA[event]]></MsgType>
26
+ <Event><![CDATA[LOCATION]]></Event>
27
+ <Latitude>23.137466</Latitude>
28
+ <Longitude>113.352425</Longitude>
29
+ <Precision>119.385040</Precision>
30
+ </xml>
31
+ )
32
+ }
33
+
34
+ let(:click_event_xml) {
35
+ %(
36
+ <xml>
37
+ <ToUserName><![CDATA[toUser]]></ToUserName>
38
+ <FromUserName><![CDATA[FromUser]]></FromUserName>
39
+ <CreateTime>123456789</CreateTime>
40
+ <MsgType><![CDATA[event]]></MsgType>
41
+ <Event><![CDATA[CLICK]]></Event>
42
+ <EventKey><![CDATA[EVENTKEY]]></EventKey>
43
+ </xml>
44
+ )
45
+ }
46
+
47
+ context "#from_xml" do
48
+ context ":subscribe_event_xml" do
49
+ # subject { MpWeixin::Event.from_xml(subscribe_event_xml) }
50
+ subject { MpWeixin::Message.from_xml(subscribe_event_xml) }
51
+
52
+ it "should return an instance of Event" do
53
+ expect(subject).to be_a(MpWeixin::Event)
54
+ end
55
+
56
+ it "should have corrent Event" do
57
+ expect(subject.Event).to eq("subscribe")
58
+ end
59
+ end
60
+
61
+ context ":location_event_xml" do
62
+ # subject { MpWeixin::Event.from_xml(location_event_xml) }
63
+ subject { MpWeixin::Message.from_xml(location_event_xml) }
64
+
65
+ it "should return an instance of Event" do
66
+ expect(subject).to be_a(MpWeixin::Event)
67
+ end
68
+
69
+ it "should have correct Event" do
70
+ expect(subject.Event).to eq("LOCATION")
71
+ end
72
+ it "should have corrent Latitude" do
73
+ expect(subject.Latitude).to eq("23.137466")
74
+ end
75
+ end
76
+
77
+ context ":click_event_xml" do
78
+ # subject { MpWeixin::Event.from_xml(click_event_xml) }
79
+ subject { MpWeixin::Message.from_xml(click_event_xml) }
80
+
81
+ it "should return an instance of Event" do
82
+ expect(subject).to be_a(MpWeixin::Event)
83
+ end
84
+
85
+ it "should have corrent Event" do
86
+ expect(subject.Event).to eq("CLICK")
87
+ end
88
+
89
+ it "should have corrent EventKey" do
90
+ expect(subject.EventKey).to eq("EVENTKEY")
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,300 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe MpWeixin::Message do
6
+
7
+ let(:text_message_xml) {
8
+ %(
9
+ <xml>
10
+ <ToUserName><![CDATA[toUser]]></ToUserName>
11
+ <FromUserName><![CDATA[fromUser]]></FromUserName>
12
+ <CreateTime>1348831860</CreateTime>
13
+ <MsgType><![CDATA[text]]></MsgType>
14
+ <Content><![CDATA[this is a test]]></Content>
15
+ <MsgId>1234567890123456</MsgId>
16
+ </xml>
17
+ )
18
+ }
19
+
20
+ let(:image_message_xml) {
21
+ %(
22
+ <xml>
23
+ <ToUserName><![CDATA[toUser]]></ToUserName>
24
+ <FromUserName><![CDATA[fromUser]]></FromUserName>
25
+ <CreateTime>1348831860</CreateTime>
26
+ <MsgType><![CDATA[image]]></MsgType>
27
+ <PicUrl><![CDATA[this is a url]]></PicUrl>
28
+ <MediaId><![CDATA[media_id]]></MediaId>
29
+ <MsgId>1234567890123456</MsgId>
30
+ </xml>
31
+ )
32
+ }
33
+
34
+ let(:voice_message_xml) {
35
+ %(
36
+ <xml>
37
+ <ToUserName><![CDATA[toUser]]></ToUserName>
38
+ <FromUserName><![CDATA[fromUser]]></FromUserName>
39
+ <CreateTime>1357290913</CreateTime>
40
+ <MsgType><![CDATA[voice]]></MsgType>
41
+ <MediaId><![CDATA[media_id]]></MediaId>
42
+ <Format><![CDATA[Format]]></Format>
43
+ <MsgId>1234567890123456</MsgId>
44
+ </xml>
45
+ )
46
+ }
47
+
48
+ let(:video_message_xml) {
49
+ %(
50
+ <xml>
51
+ <ToUserName><![CDATA[toUser]]></ToUserName>
52
+ <FromUserName><![CDATA[fromUser]]></FromUserName>
53
+ <CreateTime>1357290913</CreateTime>
54
+ <MsgType><![CDATA[video]]></MsgType>
55
+ <MediaId><![CDATA[media_id]]></MediaId>
56
+ <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
57
+ <MsgId>1234567890123456</MsgId>
58
+ </xml>
59
+ )
60
+ }
61
+
62
+ let(:location_message_xml) {
63
+ %(
64
+ <xml>
65
+ <ToUserName><![CDATA[toUser]]></ToUserName>
66
+ <FromUserName><![CDATA[fromUser]]></FromUserName>
67
+ <CreateTime>1351776360</CreateTime>
68
+ <MsgType><![CDATA[location]]></MsgType>
69
+ <Location_X>23.134521</Location_X>
70
+ <Location_Y>113.358803</Location_Y>
71
+ <Scale>20</Scale>
72
+ <Label><![CDATA[位置信息]]></Label>
73
+ <MsgId>1234567890123456</MsgId>
74
+ </xml>
75
+ )
76
+ }
77
+
78
+
79
+ let(:link_message_xml) {
80
+ %(
81
+ <xml>
82
+ <ToUserName><![CDATA[toUser]]></ToUserName>
83
+ <FromUserName><![CDATA[fromUser]]></FromUserName>
84
+ <CreateTime>1351776360</CreateTime>
85
+ <MsgType><![CDATA[link]]></MsgType>
86
+ <Title><![CDATA[公众平台官网链接]]></Title>
87
+ <Description><![CDATA[公众平台官网链接]]></Description>
88
+ <Url><![CDATA[url]]></Url>
89
+ <MsgId>1234567890123456</MsgId>
90
+ </xml>
91
+ )
92
+ }
93
+
94
+ context :reply do
95
+ let(:message) { MpWeixin::Message.from_xml(text_message_xml) }
96
+
97
+ context :reply_text_message do
98
+ subject { message.reply_text_message(Content: "hellow") }
99
+ it "should reply an text message" do
100
+ expect(subject).to be_a(MpWeixin::TextReplyMessage)
101
+ end
102
+
103
+ it "should have corrent content" do
104
+ expect(subject.Content).to eq("hellow")
105
+ end
106
+ end
107
+
108
+ context :reply_image_message do
109
+ subject { message.reply_image_message(Image: {MediaId: 'media_id'}) }
110
+ it "should reply an image message" do
111
+ expect(subject).to be_a(MpWeixin::ImageReplyMessage)
112
+ end
113
+
114
+ it "should have corrent media_id" do
115
+ expect(subject.Image.MediaId).to eq("media_id")
116
+ end
117
+ end
118
+
119
+ context :reply_voice_message do
120
+ subject { message.reply_voice_message(Voice: {MediaId: 'media_id'}) }
121
+ it "should reply an voice message" do
122
+ expect(subject).to be_a(MpWeixin::VoiceReplyMessage)
123
+ end
124
+
125
+ it "should have corrent media_id" do
126
+ expect(subject.Voice.MediaId).to eq("media_id")
127
+ end
128
+ end
129
+
130
+ context :reply_video_message do
131
+ subject do
132
+ message.reply_video_message({
133
+ Video: {
134
+ MediaId: "media_id",
135
+ Title: "title",
136
+ Description: "description"
137
+ }
138
+ })
139
+ end
140
+
141
+ it "should reply an video message" do
142
+ expect(subject).to be_a(MpWeixin::VideoReplyMessage)
143
+ end
144
+
145
+ it "should have corrent media_id" do
146
+ expect(subject.Video.MediaId).to eq("media_id")
147
+ end
148
+ end
149
+
150
+ context :reply_music_message do
151
+ subject do
152
+ message.reply_music_message({
153
+ Music: {
154
+ Title: "TITLE",
155
+ Description: "DESCRIPTION",
156
+ MusicUrl: "MUSIC_Url",
157
+ HQMusicUrl: "HQ_MUSIC_Url",
158
+ ThumbMediaId: "media_id"
159
+ }
160
+ })
161
+ end
162
+ it "should reply an music message" do
163
+ expect(subject).to be_a(MpWeixin::MusicReplyMessage)
164
+ end
165
+
166
+ it "should have corrent media_id" do
167
+ expect(subject.Music.ThumbMediaId).to eq("media_id")
168
+ end
169
+ end
170
+
171
+ context :reply_news_message do
172
+ subject do
173
+ message.reply_news_message({
174
+ ArticleCount: "2",
175
+ Articles: [
176
+ {
177
+ Title: "title1",
178
+ Description: "description1",
179
+ PicUrl: "picurl",
180
+ Url: "url"
181
+ },
182
+ {
183
+ Title: "title",
184
+ Description: "description",
185
+ PicUrl: "picurl",
186
+ Url: "url"
187
+ }
188
+ ]
189
+ })
190
+ end
191
+ it "should reply an news message" do
192
+ expect(subject).to be_a(MpWeixin::NewsReplyMessage)
193
+ end
194
+
195
+ it "should have corrent article_count" do
196
+ expect(subject.ArticleCount).to eq("2")
197
+ end
198
+
199
+ it "should have corrent title" do
200
+ expect(subject.Articles[0].Title).to eq("title1")
201
+ end
202
+ end
203
+ end
204
+
205
+ context "#from_xml" do
206
+ context ":text_message_xml" do
207
+ subject { MpWeixin::Message.from_xml(text_message_xml) }
208
+
209
+ it "should return an instance of TextMessage" do
210
+ expect(subject).to be_a(MpWeixin::TextMessage)
211
+ end
212
+
213
+ it "should have MsgType text" do
214
+ expect(subject.MsgType).to eq("text")
215
+ end
216
+ it "should have corrent Content" do
217
+ expect(subject.Content).to eq("this is a test")
218
+ end
219
+
220
+ it "should have corrent MsgId" do
221
+ expect(subject.MsgId).to eq("1234567890123456")
222
+ end
223
+ end
224
+
225
+ context ":image_message_xml" do
226
+ subject { MpWeixin::Message.from_xml(image_message_xml) }
227
+
228
+ it "should return an instance of ImageMessage" do
229
+ expect(subject).to be_a(MpWeixin::ImageMessage)
230
+ end
231
+
232
+ it "should have correct MsgType" do
233
+ expect(subject.MsgType).to eq("image")
234
+ end
235
+ it "should have corrent PicUrl" do
236
+ expect(subject.PicUrl).to eq("this is a url")
237
+ end
238
+ end
239
+
240
+ context ":voice_message_xml" do
241
+ subject { MpWeixin::Message.from_xml(voice_message_xml) }
242
+
243
+ it "should return an instance of VoiceMessage" do
244
+ expect(subject).to be_a(MpWeixin::VoiceMessage)
245
+ end
246
+
247
+ it "should have correct MsgType" do
248
+ expect(subject.MsgType).to eq("voice")
249
+ end
250
+ it "should have corrent Format" do
251
+ expect(subject.Format).to eq("Format")
252
+ end
253
+ end
254
+
255
+ context ":video_message_xml" do
256
+ subject { MpWeixin::Message.from_xml(video_message_xml) }
257
+
258
+ it "should return an instance of VoiceMessage" do
259
+ expect(subject).to be_a(MpWeixin::VideoMessage)
260
+ end
261
+
262
+ it "should have correct MsgType" do
263
+ expect(subject.MsgType).to eq("video")
264
+ end
265
+ it "should have corrent ThumbMediaId" do
266
+ expect(subject.ThumbMediaId).to eq("thumb_media_id")
267
+ end
268
+ end
269
+
270
+ context ":location_message_xml" do
271
+ subject { MpWeixin::Message.from_xml(location_message_xml) }
272
+
273
+ it "should return an instance of LocationMessage" do
274
+ expect(subject).to be_a(MpWeixin::LocationMessage)
275
+ end
276
+
277
+ it "should have correct MsgType" do
278
+ expect(subject.MsgType).to eq("location")
279
+ end
280
+ it "should have corrent Location_X" do
281
+ expect(subject.Location_X).to eq("23.134521")
282
+ end
283
+ end
284
+
285
+ context ":link_message_xml" do
286
+ subject { MpWeixin::Message.from_xml(link_message_xml) }
287
+
288
+ it "should return an instance of LinkMessage" do
289
+ expect(subject).to be_a(MpWeixin::LinkMessage)
290
+ end
291
+
292
+ it "should have correct MsgType" do
293
+ expect(subject.MsgType).to eq("link")
294
+ end
295
+ it "should have corrent Url" do
296
+ expect(subject.Url).to eq("url")
297
+ end
298
+ end
299
+ end
300
+ end