fs-facebooker 1.0.37

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 (135) hide show
  1. data/.autotest +15 -0
  2. data/CHANGELOG.rdoc +24 -0
  3. data/COPYING.rdoc +19 -0
  4. data/Manifest.txt +133 -0
  5. data/README.rdoc +104 -0
  6. data/Rakefile +85 -0
  7. data/TODO.rdoc +4 -0
  8. data/examples/desktop_login.rb +14 -0
  9. data/facebooker.gemspec +38 -0
  10. data/generators/facebook/facebook_generator.rb +14 -0
  11. data/generators/facebook/templates/config/facebooker.yml +49 -0
  12. data/generators/facebook/templates/public/javascripts/facebooker.js +83 -0
  13. data/generators/facebook_controller/USAGE +33 -0
  14. data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
  15. data/generators/facebook_controller/templates/controller.rb +7 -0
  16. data/generators/facebook_controller/templates/functional_test.rb +11 -0
  17. data/generators/facebook_controller/templates/helper.rb +2 -0
  18. data/generators/facebook_controller/templates/view.fbml.erb +2 -0
  19. data/generators/facebook_controller/templates/view.html.erb +2 -0
  20. data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
  21. data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
  22. data/generators/facebook_publisher/templates/publisher.rb +3 -0
  23. data/generators/facebook_scaffold/USAGE +27 -0
  24. data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
  25. data/generators/facebook_scaffold/templates/controller.rb +93 -0
  26. data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
  27. data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
  28. data/generators/facebook_scaffold/templates/helper.rb +2 -0
  29. data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
  30. data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
  31. data/generators/facebook_scaffold/templates/style.css +74 -0
  32. data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
  33. data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
  34. data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
  35. data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
  36. data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
  37. data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
  38. data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
  39. data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
  40. data/generators/publisher/publisher_generator.rb +14 -0
  41. data/generators/xd_receiver/templates/xd_receiver.html +10 -0
  42. data/generators/xd_receiver/xd_receiver_generator.rb +10 -0
  43. data/init.rb +25 -0
  44. data/install.rb +12 -0
  45. data/lib/facebooker.rb +179 -0
  46. data/lib/facebooker/adapters/adapter_base.rb +91 -0
  47. data/lib/facebooker/adapters/bebo_adapter.rb +77 -0
  48. data/lib/facebooker/adapters/facebook_adapter.rb +52 -0
  49. data/lib/facebooker/admin.rb +42 -0
  50. data/lib/facebooker/batch_request.rb +45 -0
  51. data/lib/facebooker/data.rb +57 -0
  52. data/lib/facebooker/feed.rb +78 -0
  53. data/lib/facebooker/logging.rb +44 -0
  54. data/lib/facebooker/mobile.rb +20 -0
  55. data/lib/facebooker/mock/service.rb +50 -0
  56. data/lib/facebooker/mock/session.rb +18 -0
  57. data/lib/facebooker/model.rb +139 -0
  58. data/lib/facebooker/models/affiliation.rb +10 -0
  59. data/lib/facebooker/models/album.rb +11 -0
  60. data/lib/facebooker/models/applicationproperties.rb +39 -0
  61. data/lib/facebooker/models/applicationrestrictions.rb +10 -0
  62. data/lib/facebooker/models/cookie.rb +10 -0
  63. data/lib/facebooker/models/education_info.rb +11 -0
  64. data/lib/facebooker/models/event.rb +28 -0
  65. data/lib/facebooker/models/friend_list.rb +16 -0
  66. data/lib/facebooker/models/group.rb +36 -0
  67. data/lib/facebooker/models/info_item.rb +10 -0
  68. data/lib/facebooker/models/info_section.rb +10 -0
  69. data/lib/facebooker/models/location.rb +8 -0
  70. data/lib/facebooker/models/notifications.rb +17 -0
  71. data/lib/facebooker/models/page.rb +28 -0
  72. data/lib/facebooker/models/photo.rb +19 -0
  73. data/lib/facebooker/models/tag.rb +12 -0
  74. data/lib/facebooker/models/user.rb +497 -0
  75. data/lib/facebooker/models/video.rb +9 -0
  76. data/lib/facebooker/models/work_info.rb +10 -0
  77. data/lib/facebooker/parser.rb +642 -0
  78. data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
  79. data/lib/facebooker/rails/controller.rb +344 -0
  80. data/lib/facebooker/rails/cucumber.rb +28 -0
  81. data/lib/facebooker/rails/cucumber/world.rb +46 -0
  82. data/lib/facebooker/rails/extensions/action_controller.rb +48 -0
  83. data/lib/facebooker/rails/extensions/rack_setup.rb +6 -0
  84. data/lib/facebooker/rails/extensions/routing.rb +15 -0
  85. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  86. data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
  87. data/lib/facebooker/rails/facebook_request_fix.rb +30 -0
  88. data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
  89. data/lib/facebooker/rails/facebook_session_handling.rb +68 -0
  90. data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
  91. data/lib/facebooker/rails/facebook_url_rewriting.rb +60 -0
  92. data/lib/facebooker/rails/helpers.rb +794 -0
  93. data/lib/facebooker/rails/helpers/fb_connect.rb +118 -0
  94. data/lib/facebooker/rails/integration_session.rb +38 -0
  95. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  96. data/lib/facebooker/rails/publisher.rb +550 -0
  97. data/lib/facebooker/rails/routing.rb +49 -0
  98. data/lib/facebooker/rails/test_helpers.rb +68 -0
  99. data/lib/facebooker/rails/utilities.rb +22 -0
  100. data/lib/facebooker/server_cache.rb +24 -0
  101. data/lib/facebooker/service.rb +102 -0
  102. data/lib/facebooker/session.rb +606 -0
  103. data/lib/facebooker/version.rb +9 -0
  104. data/lib/net/http_multipart_post.rb +123 -0
  105. data/lib/rack/facebook.rb +77 -0
  106. data/lib/tasks/facebooker.rake +18 -0
  107. data/lib/tasks/tunnel.rake +46 -0
  108. data/rails/init.rb +1 -0
  109. data/setup.rb +1585 -0
  110. data/templates/layout.erb +24 -0
  111. data/test/facebooker/adapters_test.rb +96 -0
  112. data/test/facebooker/admin_test.rb +102 -0
  113. data/test/facebooker/batch_request_test.rb +83 -0
  114. data/test/facebooker/data_test.rb +86 -0
  115. data/test/facebooker/logging_test.rb +43 -0
  116. data/test/facebooker/mobile_test.rb +45 -0
  117. data/test/facebooker/model_test.rb +133 -0
  118. data/test/facebooker/models/event_test.rb +15 -0
  119. data/test/facebooker/models/photo_test.rb +16 -0
  120. data/test/facebooker/models/user_test.rb +343 -0
  121. data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +24 -0
  122. data/test/facebooker/rails/facebook_url_rewriting_test.rb +39 -0
  123. data/test/facebooker/rails/publisher_test.rb +481 -0
  124. data/test/facebooker/rails_integration_test.rb +1398 -0
  125. data/test/facebooker/server_cache_test.rb +44 -0
  126. data/test/facebooker/session_test.rb +614 -0
  127. data/test/facebooker_test.rb +951 -0
  128. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  129. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  130. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  131. data/test/net/http_multipart_post_test.rb +52 -0
  132. data/test/rack/facebook_test.rb +61 -0
  133. data/test/rails_test_helper.rb +27 -0
  134. data/test/test_helper.rb +74 -0
  135. metadata +232 -0
@@ -0,0 +1,9 @@
1
+ require 'facebooker/model'
2
+ module Facebooker
3
+ class Video
4
+ include Model
5
+ attr_accessor :vid, :owner, :title,
6
+ :link, :description, :created,
7
+ :story_fbid
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Facebooker
2
+ class WorkInfo
3
+ include Model
4
+ attr_accessor :end_date, :start_date, :company_name, :description, :position
5
+ attr_reader :location
6
+ def location=(location)
7
+ @location = location.kind_of?(Hash) ? Location.from_hash(location) : location
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,642 @@
1
+ require 'rexml/document'
2
+ require 'facebooker/session'
3
+ module Facebooker
4
+ class Parser
5
+
6
+ module REXMLElementExtensions # :nodoc:
7
+ def content
8
+ self.text || ''
9
+ end
10
+
11
+ def [] key
12
+ attributes[key]
13
+ end
14
+
15
+ def text?
16
+ false
17
+ end
18
+ end
19
+
20
+ module REXMLTextExtensions # :nodoc:
21
+ def text?
22
+ true
23
+ end
24
+ end
25
+
26
+ ::REXML::Element.__send__(:include, REXMLElementExtensions)
27
+ ::REXML::Text.__send__(:include, REXMLTextExtensions)
28
+
29
+ def self.parse(method, data)
30
+ Errors.process(data)
31
+ parser = Parser::PARSERS[method]
32
+ raise "Can't find a parser for '#{method}'" unless parser
33
+ parser.process(data)
34
+ end
35
+
36
+ def self.array_of(response_element, element_name)
37
+ values_to_return = []
38
+ response_element.children.each do |element|
39
+ next if element.text?
40
+ next unless element.name == element_name
41
+ values_to_return << yield(element)
42
+ end
43
+ values_to_return
44
+ end
45
+
46
+ def self.array_of_text_values(response_element, element_name)
47
+ array_of(response_element, element_name) do |element|
48
+ element.content.strip
49
+ end
50
+ end
51
+
52
+ def self.array_of_hashes(response_element, element_name)
53
+ array_of(response_element, element_name) do |element|
54
+ hashinate(element)
55
+ end
56
+ end
57
+
58
+ def self.element(name, data)
59
+ data = data.body rescue data # either data or an HTTP response
60
+ begin
61
+ node = Nokogiri::XML(data.strip).at(name)
62
+ return node if node
63
+ rescue # Can't parse with Nokogiri
64
+ doc = REXML::Document.new(data)
65
+ doc.elements.each(name) do |element|
66
+ return element
67
+ end
68
+ end
69
+ raise "Element #{name} not found in #{data}"
70
+ end
71
+
72
+ def self.hash_or_value_for(element)
73
+ if element.children.size == 1 && element.children.first.text?
74
+ element.content.strip
75
+ else
76
+ hashinate(element)
77
+ end
78
+ end
79
+
80
+ def self.hashinate(response_element)
81
+ response_element.children.reject{|c| c.text? }.inject({}) do |hash, child|
82
+ # If the node hasn't any child, and is not a list, we want empty strings, not empty hashes,
83
+ # except if attributes['nil'] == true
84
+ hash[child.name] =
85
+ if (child['nil'] == 'true')
86
+ nil
87
+ elsif (child.children.size == 1 && child.children.first.text?) || (child.children.size == 0 && child['list'] != 'true')
88
+ anonymous_field_from(child, hash) || child.content.strip
89
+ elsif child['list'] == 'true'
90
+ child.children.reject{|c| c.text? }.map { |subchild| hash_or_value_for(subchild)}
91
+ else
92
+ child.children.reject{|c| c.text? }.inject({}) do |subhash, subchild|
93
+ subhash[subchild.name] = hash_or_value_for(subchild)
94
+ subhash
95
+ end
96
+ end #if (child.attributes)
97
+ hash
98
+ end #do |hash, child|
99
+ end
100
+
101
+ def self.booleanize(response)
102
+ response == "1" ? true : false
103
+ end
104
+
105
+ def self.anonymous_field_from(child, hash)
106
+ if child.name == 'anon'
107
+ (hash[child.name] || []) << child.content.strip
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ class RevokeAuthorization < Parser#:nodoc:
114
+ def self.process(data)
115
+ booleanize(data)
116
+ end
117
+ end
118
+
119
+ class CreateToken < Parser#:nodoc:
120
+ def self.process(data)
121
+ element('auth_createToken_response', data).content.strip
122
+ end
123
+ end
124
+
125
+ class RegisterUsers < Parser
126
+ def self.process(data)
127
+ array_of_text_values(element("connect_registerUsers_response", data), "connect_registerUsers_response_elt")
128
+ end
129
+ end
130
+
131
+ class UnregisterUsers < Parser
132
+ def self.process(data)
133
+ array_of_text_values(element("connect_unregisterUsers_response", data), "connect_unregisterUsers_response_elt")
134
+ end
135
+ end
136
+
137
+ class GetUnconnectedFriendsCount < Parser
138
+ def self.process(data)
139
+ hash_or_value_for(element("connect_getUnconnectedFriendsCount_response",data)).to_i
140
+ end
141
+ end
142
+
143
+ class GetSession < Parser#:nodoc:
144
+ def self.process(data)
145
+ hashinate(element('auth_getSession_response', data))
146
+ end
147
+ end
148
+
149
+ class GetFriends < Parser#:nodoc:
150
+ def self.process(data)
151
+ array_of_text_values(element('friends_get_response', data), 'uid')
152
+ end
153
+ end
154
+
155
+ class FriendListsGet < Parser#:nodoc:
156
+ def self.process(data)
157
+ array_of_hashes(element('friends_getLists_response', data), 'friendlist')
158
+ end
159
+ end
160
+
161
+ class UserInfo < Parser#:nodoc:
162
+ def self.process(data)
163
+ array_of_hashes(element('users_getInfo_response', data), 'user')
164
+ end
165
+ end
166
+
167
+ class UserStandardInfo < Parser#:nodoc:
168
+ def self.process(data)
169
+ array_of_hashes(element('users_getStandardInfo_response', data), 'standard_user_info')
170
+ end
171
+ end
172
+
173
+ class GetLoggedInUser < Parser#:nodoc:
174
+ def self.process(data)
175
+ Integer(element('users_getLoggedInUser_response', data).content.strip)
176
+ end
177
+ end
178
+
179
+ class PagesIsAdmin < Parser#:nodoc:
180
+ def self.process(data)
181
+ element('pages_isAdmin_response', data).content.strip == '1'
182
+ end
183
+ end
184
+
185
+ class PagesGetInfo < Parser#:nodoc:
186
+ def self.process(data)
187
+ array_of_hashes(element('pages_getInfo_response', data), 'page')
188
+ end
189
+ end
190
+
191
+ class PagesIsFan < Parser#:nodoc:
192
+ def self.process(data)
193
+ element('pages_isFan_response', data).content.strip == '1'
194
+ end
195
+ end
196
+
197
+ class PublishStoryToUser < Parser#:nodoc:
198
+ def self.process(data)
199
+ element('feed_publishStoryToUser_response', data).content.strip
200
+ end
201
+ end
202
+
203
+ class StreamPublish < Parser#:nodoc:
204
+ def self.process(data)
205
+ element('stream_publish_response', data).content.strip
206
+ end
207
+ end
208
+
209
+ class RegisterTemplateBundle < Parser#:nodoc:
210
+ def self.process(data)
211
+ element('feed_registerTemplateBundle_response', data).content.to_i
212
+ end
213
+ end
214
+
215
+ class GetRegisteredTemplateBundles < Parser
216
+ def self.process(data)
217
+ array_of_hashes(element('feed_getRegisteredTemplateBundles_response',data), 'template_bundle')
218
+ end
219
+ end
220
+
221
+ class DeactivateTemplateBundleByID < Parser#:nodoc:
222
+ def self.process(data)
223
+ element('feed_deactivateTemplateBundleByID_response', data).content.strip == '1'
224
+ end
225
+ end
226
+
227
+ class PublishUserAction < Parser#:nodoc:
228
+ def self.process(data)
229
+ element('feed_publishUserAction_response', data).children[1].content.strip == "1"
230
+ end
231
+ end
232
+
233
+ class PublishActionOfUser < Parser#:nodoc:
234
+ def self.process(data)
235
+ element('feed_publishActionOfUser_response', data).content.strip
236
+ end
237
+ end
238
+
239
+ class PublishTemplatizedAction < Parser#:nodoc:
240
+ def self.process(data)
241
+ element('feed_publishTemplatizedAction_response', data).children[1].content.strip
242
+ end
243
+ end
244
+
245
+ class SetAppProperties < Parser#:nodoc:
246
+ def self.process(data)
247
+ element('admin_setAppProperties_response', data).content.strip
248
+ end
249
+ end
250
+
251
+ class GetAppProperties < Parser#:nodoc:
252
+ def self.process(data)
253
+ element('admin_getAppProperties_response', data).content.strip
254
+ end
255
+ end
256
+
257
+ class SetRestrictionInfo < Parser#:nodoc:
258
+ def self.process(data)
259
+ element('admin_setRestrictionInfo_response', data).content.strip
260
+ end
261
+ end
262
+
263
+ class GetRestrictionInfo < Parser#:nodoc:
264
+ def self.process(data)
265
+ element('admin_getRestrictionInfo_response', data).content.strip
266
+ end
267
+ end
268
+
269
+ class GetAllocation < Parser#:nodoc:
270
+ def self.process(data)
271
+ element('admin_getAllocation_response', data).content.strip
272
+ end
273
+ end
274
+
275
+ class BatchRun < Parser #:nodoc:
276
+ class << self
277
+ def current_batch=(current_batch)
278
+ Thread.current[:facebooker_current_batch]=current_batch
279
+ end
280
+ def current_batch
281
+ Thread.current[:facebooker_current_batch]
282
+ end
283
+ end
284
+ def self.process(data)
285
+ array_of_text_values(element('batch_run_response',data),"batch_run_response_elt").each_with_index do |response,i|
286
+ batch_request=current_batch[i]
287
+ body=Struct.new(:body).new
288
+ body.body=CGI.unescapeHTML(response)
289
+ begin
290
+ batch_request.result=Parser.parse(batch_request.method,body)
291
+ rescue Exception=>ex
292
+ batch_request.exception_raised=ex
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ class GetAppUsers < Parser#:nodoc:
299
+ def self.process(data)
300
+ array_of_text_values(element('friends_getAppUsers_response', data), 'uid')
301
+ end
302
+ end
303
+
304
+ class NotificationsGet < Parser#:nodoc:
305
+ def self.process(data)
306
+ hashinate(element('notifications_get_response', data))
307
+ end
308
+ end
309
+
310
+ class NotificationsSend < Parser#:nodoc:
311
+ def self.process(data)
312
+ element('notifications_send_response', data).content.strip
313
+ end
314
+ end
315
+
316
+ class NotificationsSendEmail < Parser#:nodoc:
317
+ def self.process(data)
318
+ element('notifications_sendEmail_response', data).content.strip
319
+ end
320
+ end
321
+
322
+ class GetTags < Parser#nodoc:
323
+ def self.process(data)
324
+ array_of_hashes(element('photos_getTags_response', data), 'photo_tag')
325
+ end
326
+ end
327
+
328
+ class AddTags < Parser#nodoc:
329
+ def self.process(data)
330
+ element('photos_addTag_response', data)
331
+ end
332
+ end
333
+
334
+ class GetPhotos < Parser#nodoc:
335
+ def self.process(data)
336
+ array_of_hashes(element('photos_get_response', data), 'photo')
337
+ end
338
+ end
339
+
340
+ class GetAlbums < Parser#nodoc:
341
+ def self.process(data)
342
+ array_of_hashes(element('photos_getAlbums_response', data), 'album')
343
+ end
344
+ end
345
+
346
+ class CreateAlbum < Parser#:nodoc:
347
+ def self.process(data)
348
+ hashinate(element('photos_createAlbum_response', data))
349
+ end
350
+ end
351
+
352
+ class UploadPhoto < Parser#:nodoc:
353
+ def self.process(data)
354
+ hashinate(element('photos_upload_response', data))
355
+ end
356
+ end
357
+
358
+ class UploadVideo < Parser#:nodoc:
359
+ def self.process(data)
360
+ hashinate(element('video_upload_response', data))
361
+ end
362
+ end
363
+
364
+ class SendRequest < Parser#:nodoc:
365
+ def self.process(data)
366
+ element('notifications_sendRequest_response', data).content.strip
367
+ end
368
+ end
369
+
370
+ class ProfileFBML < Parser#:nodoc:
371
+ def self.process(data)
372
+ element('profile_getFBML_response', data).content.strip
373
+ end
374
+ end
375
+
376
+ class ProfileFBMLSet < Parser#:nodoc:
377
+ def self.process(data)
378
+ element('profile_setFBML_response', data).content.strip
379
+ end
380
+ end
381
+
382
+ class ProfileInfo < Parser#:nodoc:
383
+ def self.process(data)
384
+ hashinate(element('profile_getInfo_response info_fields', data))
385
+ end
386
+ end
387
+
388
+ class ProfileInfoSet < Parser#:nodoc:
389
+ def self.process(data)
390
+ element('profile_setInfo_response', data).content.strip
391
+ end
392
+ end
393
+
394
+ class FqlQuery < Parser#nodoc
395
+ def self.process(data)
396
+ root = element('fql_query_response', data)
397
+ first_child = root.children.reject{|c| c.text? }.first
398
+ first_child.nil? ? [] : [first_child.name, array_of_hashes(root, first_child.name)]
399
+ end
400
+ end
401
+
402
+ class SetRefHandle < Parser#:nodoc:
403
+ def self.process(data)
404
+ element('fbml_setRefHandle_response', data).content.strip
405
+ end
406
+ end
407
+
408
+ class RefreshRefURL < Parser#:nodoc:
409
+ def self.process(data)
410
+ element('fbml_refreshRefUrl_response', data).content.strip
411
+ end
412
+ end
413
+
414
+ class RefreshImgSrc < Parser#:nodoc:
415
+ def self.process(data)
416
+ element('fbml_refreshImgSrc_response', data).content.strip
417
+ end
418
+ end
419
+
420
+ class SetCookie < Parser#:nodoc:
421
+ def self.process(data)
422
+ element('data_setCookie_response', data).content.strip
423
+ end
424
+ end
425
+
426
+ class GetCookies < Parser#:nodoc:
427
+ def self.process(data)
428
+ array_of_hashes(element('data_getCookie_response', data), 'cookies')
429
+ end
430
+ end
431
+
432
+ class EventsGet < Parser#:nodoc:
433
+ def self.process(data)
434
+ array_of_hashes(element('events_get_response', data), 'event')
435
+ end
436
+ end
437
+
438
+ class GroupGetMembers < Parser#:nodoc:
439
+ def self.process(data)
440
+ root = element('groups_getMembers_response', data)
441
+ result = ['members', 'admins', 'officers', 'not_replied'].map do |position|
442
+ array_of(root, position) {|element| element}.map do |element|
443
+ array_of_text_values(element, 'uid').map do |uid|
444
+ {:position => position}.merge(:uid => uid)
445
+ end
446
+ end
447
+ end.flatten
448
+ end
449
+ end
450
+
451
+ class EventMembersGet < Parser#:nodoc:
452
+ def self.process(data)
453
+ root = element('events_getMembers_response', data)
454
+ result = ['attending', 'declined', 'unsure', 'not_replied'].map do |rsvp_status|
455
+ array_of(root, rsvp_status) {|element| element}.map do |element|
456
+ array_of_text_values(element, 'uid').map do |uid|
457
+ {:rsvp_status => rsvp_status}.merge(:uid => uid)
458
+ end
459
+ end
460
+ end.flatten
461
+ end
462
+ end
463
+
464
+ class GroupsGet < Parser#:nodoc:
465
+ def self.process(data)
466
+ array_of_hashes(element('groups_get_response', data), 'group')
467
+ end
468
+ end
469
+
470
+ class AreFriends < Parser#:nodoc:
471
+ def self.process(data)
472
+ array_of_hashes(element('friends_areFriends_response', data), 'friend_info').inject({}) do |memo, hash|
473
+ memo[[Integer(hash['uid1']), Integer(hash['uid2'])].sort] = are_friends?(hash['are_friends'])
474
+ memo
475
+ end
476
+ end
477
+
478
+ private
479
+ def self.are_friends?(raw_value)
480
+ if raw_value == '1'
481
+ true
482
+ elsif raw_value == '0'
483
+ false
484
+ else
485
+ nil
486
+ end
487
+ end
488
+ end
489
+
490
+ class SetStatus < Parser
491
+ def self.process(data)
492
+ element('users_setStatus_response',data).content.strip == '1'
493
+ end
494
+ end
495
+
496
+ class GetPreference < Parser#:nodoc:
497
+ def self.process(data)
498
+ element('data_getUserPreference_response', data).content.strip
499
+ end
500
+ end
501
+
502
+ class SetPreference < Parser#:nodoc:
503
+ def self.process(data)
504
+ element('data_setUserPreference_response', data).content.strip
505
+ end
506
+ end
507
+
508
+ class UserHasPermission < Parser
509
+ def self.process(data)
510
+ element('users_hasAppPermission_response', data).content.strip
511
+ end
512
+ end
513
+
514
+ class SmsSend < Parser#:nodoc:
515
+ def self.process(data)
516
+ element('sms_send_response', data).content.strip == '0'
517
+ end
518
+ end
519
+
520
+ class SmsCanSend < Parser#:nodoc:
521
+ def self.process(data)
522
+ element('sms_canSend_response', data).content.strip
523
+ end
524
+ end
525
+
526
+ class Errors < Parser#:nodoc:
527
+ EXCEPTIONS = {
528
+ 1 => Facebooker::Session::UnknownError,
529
+ 2 => Facebooker::Session::ServiceUnavailable,
530
+ 4 => Facebooker::Session::MaxRequestsDepleted,
531
+ 5 => Facebooker::Session::HostNotAllowed,
532
+ 100 => Facebooker::Session::MissingOrInvalidParameter,
533
+ 101 => Facebooker::Session::InvalidAPIKey,
534
+ 102 => Facebooker::Session::SessionExpired,
535
+ 103 => Facebooker::Session::CallOutOfOrder,
536
+ 104 => Facebooker::Session::IncorrectSignature,
537
+ 120 => Facebooker::Session::InvalidAlbumId,
538
+ 250 => Facebooker::Session::ExtendedPermissionRequired,
539
+ 321 => Facebooker::Session::AlbumIsFull,
540
+ 324 => Facebooker::Session::MissingOrInvalidImageFile,
541
+ 325 => Facebooker::Session::TooManyUnapprovedPhotosPending,
542
+ 330 => Facebooker::Session::TemplateDataMissingRequiredTokens,
543
+ 340 => Facebooker::Session::TooManyUserCalls,
544
+ 341 => Facebooker::Session::TooManyUserActionCalls,
545
+ 342 => Facebooker::Session::InvalidFeedTitleLink,
546
+ 343 => Facebooker::Session::InvalidFeedTitleLength,
547
+ 344 => Facebooker::Session::InvalidFeedTitleName,
548
+ 345 => Facebooker::Session::BlankFeedTitle,
549
+ 346 => Facebooker::Session::FeedBodyLengthTooLong,
550
+ 347 => Facebooker::Session::InvalidFeedPhotoSource,
551
+ 348 => Facebooker::Session::InvalidFeedPhotoLink,
552
+ 330 => Facebooker::Session::FeedMarkupInvalid,
553
+ 360 => Facebooker::Session::FeedTitleDataInvalid,
554
+ 361 => Facebooker::Session::FeedTitleTemplateInvalid,
555
+ 362 => Facebooker::Session::FeedBodyDataInvalid,
556
+ 363 => Facebooker::Session::FeedBodyTemplateInvalid,
557
+ 364 => Facebooker::Session::FeedPhotosNotRetrieved,
558
+ 366 => Facebooker::Session::FeedTargetIdsInvalid,
559
+ 601 => Facebooker::Session::FQLParseError,
560
+ 602 => Facebooker::Session::FQLFieldDoesNotExist,
561
+ 603 => Facebooker::Session::FQLTableDoesNotExist,
562
+ 604 => Facebooker::Session::FQLStatementNotIndexable,
563
+ 605 => Facebooker::Session::FQLFunctionDoesNotExist,
564
+ 606 => Facebooker::Session::FQLWrongNumberArgumentsPassedToFunction,
565
+ 807 => Facebooker::Session::TemplateBundleInvalid
566
+ }
567
+ def self.process(data)
568
+ response_element = element('error_response', data) rescue nil
569
+ if response_element
570
+ hash = hashinate(response_element)
571
+ exception = EXCEPTIONS[Integer(hash['error_code'])] || StandardError
572
+ raise exception, hash['error_msg']
573
+ end
574
+ end
575
+ end
576
+
577
+ class Parser
578
+ PARSERS = {
579
+ 'facebook.auth.revokeAuthorization' => RevokeAuthorization,
580
+ 'facebook.auth.createToken' => CreateToken,
581
+ 'facebook.auth.getSession' => GetSession,
582
+ 'facebook.connect.registerUsers' => RegisterUsers,
583
+ 'facebook.connect.unregisterUsers' => UnregisterUsers,
584
+ 'facebook.connect.getUnconnectedFriendsCount' => GetUnconnectedFriendsCount,
585
+ 'facebook.users.getInfo' => UserInfo,
586
+ 'facebook.users.getStandardInfo' => UserStandardInfo,
587
+ 'facebook.users.setStatus' => SetStatus,
588
+ 'facebook.users.getLoggedInUser' => GetLoggedInUser,
589
+ 'facebook.users.hasAppPermission' => UserHasPermission,
590
+ 'facebook.pages.isAdmin' => PagesIsAdmin,
591
+ 'facebook.pages.getInfo' => PagesGetInfo,
592
+ 'facebook.pages.isFan' => PagesIsFan,
593
+ 'facebook.friends.get' => GetFriends,
594
+ 'facebook.friends.getLists' => FriendListsGet,
595
+ 'facebook.friends.areFriends' => AreFriends,
596
+ 'facebook.friends.getAppUsers' => GetAppUsers,
597
+ 'facebook.feed.publishStoryToUser' => PublishStoryToUser,
598
+ 'facebook.feed.publishActionOfUser' => PublishActionOfUser,
599
+ 'facebook.feed.publishTemplatizedAction' => PublishTemplatizedAction,
600
+ 'facebook.feed.registerTemplateBundle' => RegisterTemplateBundle,
601
+ 'facebook.feed.deactivateTemplateBundleByID' => DeactivateTemplateBundleByID,
602
+ 'facebook.feed.getRegisteredTemplateBundles' => GetRegisteredTemplateBundles,
603
+ 'facebook.feed.publishUserAction' => PublishUserAction,
604
+ 'facebook.notifications.get' => NotificationsGet,
605
+ 'facebook.notifications.send' => NotificationsSend,
606
+ 'facebook.notifications.sendRequest' => SendRequest,
607
+ 'facebook.profile.getFBML' => ProfileFBML,
608
+ 'facebook.profile.setFBML' => ProfileFBMLSet,
609
+ 'facebook.profile.getInfo' => ProfileInfo,
610
+ 'facebook.profile.setInfo' => ProfileInfoSet,
611
+ 'facebook.fbml.setRefHandle' => SetRefHandle,
612
+ 'facebook.fbml.refreshRefUrl' => RefreshRefURL,
613
+ 'facebook.fbml.refreshImgSrc' => RefreshImgSrc,
614
+ 'facebook.data.setCookie' => SetCookie,
615
+ 'facebook.data.getCookies' => GetCookies,
616
+ 'facebook.admin.setAppProperties' => SetAppProperties,
617
+ 'facebook.admin.getAppProperties' => GetAppProperties,
618
+ 'facebook.admin.setRestrictionInfo' => SetRestrictionInfo,
619
+ 'facebook.admin.getRestrictionInfo' => GetRestrictionInfo,
620
+ 'facebook.admin.getAllocation' => GetAllocation,
621
+ 'facebook.batch.run' => BatchRun,
622
+ 'facebook.fql.query' => FqlQuery,
623
+ 'facebook.photos.get' => GetPhotos,
624
+ 'facebook.photos.getAlbums' => GetAlbums,
625
+ 'facebook.photos.createAlbum' => CreateAlbum,
626
+ 'facebook.photos.getTags' => GetTags,
627
+ 'facebook.photos.addTag' => AddTags,
628
+ 'facebook.photos.upload' => UploadPhoto,
629
+ 'facebook.stream.publish' => StreamPublish,
630
+ 'facebook.events.get' => EventsGet,
631
+ 'facebook.groups.get' => GroupsGet,
632
+ 'facebook.events.getMembers' => EventMembersGet,
633
+ 'facebook.groups.getMembers' => GroupGetMembers,
634
+ 'facebook.notifications.sendEmail' => NotificationsSendEmail,
635
+ 'facebook.data.getUserPreference' => GetPreference,
636
+ 'facebook.data.setUserPreference' => SetPreference,
637
+ 'facebook.video.upload' => UploadVideo,
638
+ 'facebook.sms.send' => SmsSend,
639
+ 'facebook.sms.canSend' => SmsCanSend
640
+ }
641
+ end
642
+ end