fbooker 1.0.53

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