simianarmy-facebooker 1.0.40

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 +113 -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 +93 -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 +26 -0
  44. data/install.rb +12 -0
  45. data/lib/facebooker/adapters/adapter_base.rb +91 -0
  46. data/lib/facebooker/adapters/bebo_adapter.rb +77 -0
  47. data/lib/facebooker/adapters/facebook_adapter.rb +52 -0
  48. data/lib/facebooker/admin.rb +42 -0
  49. data/lib/facebooker/batch_request.rb +45 -0
  50. data/lib/facebooker/data.rb +57 -0
  51. data/lib/facebooker/feed.rb +78 -0
  52. data/lib/facebooker/logging.rb +44 -0
  53. data/lib/facebooker/mobile.rb +20 -0
  54. data/lib/facebooker/mock/service.rb +50 -0
  55. data/lib/facebooker/mock/session.rb +18 -0
  56. data/lib/facebooker/model.rb +139 -0
  57. data/lib/facebooker/models/affiliation.rb +10 -0
  58. data/lib/facebooker/models/album.rb +11 -0
  59. data/lib/facebooker/models/applicationproperties.rb +39 -0
  60. data/lib/facebooker/models/applicationrestrictions.rb +10 -0
  61. data/lib/facebooker/models/cookie.rb +10 -0
  62. data/lib/facebooker/models/education_info.rb +11 -0
  63. data/lib/facebooker/models/event.rb +28 -0
  64. data/lib/facebooker/models/friend_list.rb +16 -0
  65. data/lib/facebooker/models/group.rb +36 -0
  66. data/lib/facebooker/models/info_item.rb +10 -0
  67. data/lib/facebooker/models/info_section.rb +10 -0
  68. data/lib/facebooker/models/location.rb +8 -0
  69. data/lib/facebooker/models/notifications.rb +17 -0
  70. data/lib/facebooker/models/page.rb +28 -0
  71. data/lib/facebooker/models/photo.rb +19 -0
  72. data/lib/facebooker/models/tag.rb +12 -0
  73. data/lib/facebooker/models/user.rb +469 -0
  74. data/lib/facebooker/models/video.rb +9 -0
  75. data/lib/facebooker/models/work_info.rb +10 -0
  76. data/lib/facebooker/parser.rb +650 -0
  77. data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
  78. data/lib/facebooker/rails/controller.rb +356 -0
  79. data/lib/facebooker/rails/cucumber/world.rb +46 -0
  80. data/lib/facebooker/rails/cucumber.rb +28 -0
  81. data/lib/facebooker/rails/extensions/action_controller.rb +48 -0
  82. data/lib/facebooker/rails/extensions/rack_setup.rb +6 -0
  83. data/lib/facebooker/rails/extensions/routing.rb +15 -0
  84. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  85. data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
  86. data/lib/facebooker/rails/facebook_request_fix.rb +28 -0
  87. data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
  88. data/lib/facebooker/rails/facebook_session_handling.rb +68 -0
  89. data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
  90. data/lib/facebooker/rails/facebook_url_rewriting.rb +60 -0
  91. data/lib/facebooker/rails/helpers/fb_connect.rb +118 -0
  92. data/lib/facebooker/rails/helpers.rb +804 -0
  93. data/lib/facebooker/rails/integration_session.rb +38 -0
  94. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  95. data/lib/facebooker/rails/publisher.rb +550 -0
  96. data/lib/facebooker/rails/routing.rb +49 -0
  97. data/lib/facebooker/rails/test_helpers.rb +68 -0
  98. data/lib/facebooker/rails/utilities.rb +22 -0
  99. data/lib/facebooker/server_cache.rb +24 -0
  100. data/lib/facebooker/service.rb +102 -0
  101. data/lib/facebooker/session.rb +635 -0
  102. data/lib/facebooker/version.rb +9 -0
  103. data/lib/facebooker.rb +179 -0
  104. data/lib/net/http_multipart_post.rb +123 -0
  105. data/lib/rack/facebook.rb +82 -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 +174 -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 +361 -0
  121. data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +25 -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 +1434 -0
  125. data/test/facebooker/server_cache_test.rb +44 -0
  126. data/test/facebooker/session_test.rb +652 -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 +222 -0
@@ -0,0 +1,356 @@
1
+ require 'facebooker'
2
+ require 'facebooker/rails/profile_publisher_extensions'
3
+ module Facebooker
4
+ module Rails
5
+ module Controller
6
+ include Facebooker::Rails::BackwardsCompatibleParamChecks
7
+ include Facebooker::Rails::ProfilePublisherExtensions
8
+ def self.included(controller)
9
+ controller.extend(ClassMethods)
10
+ controller.before_filter :set_adapter
11
+ controller.before_filter :set_facebook_request_format
12
+ controller.helper_attr :facebook_session_parameters
13
+ controller.helper_method :request_comes_from_facebook?
14
+ end
15
+
16
+ def initialize *args
17
+ @facebook_session = nil
18
+ @installation_required = nil
19
+ super
20
+ end
21
+
22
+ def facebook_session
23
+ @facebook_session
24
+ end
25
+
26
+ def facebook_session_parameters
27
+ {:fb_sig_session_key=>params[:fb_sig_session_key]}
28
+ end
29
+
30
+ def create_facebook_session
31
+ secure_with_facebook_params! || secure_with_cookies! || secure_with_token!
32
+ end
33
+
34
+ #this is used to proxy a connection through a rails app so the facebook secret key is not needed
35
+ #iphone apps use this
36
+ def create_facebook_session_with_secret
37
+ secure_with_session_secret!
38
+ end
39
+
40
+ def set_facebook_session
41
+ # first, see if we already have a session
42
+ session_set = session_already_secured?
43
+ # if not, see if we can load it from the environment
44
+ unless session_set
45
+ session_set = create_facebook_session
46
+ session[:facebook_session] = @facebook_session if session_set
47
+ end
48
+ if session_set
49
+ capture_facebook_friends_if_available!
50
+ Session.current = facebook_session
51
+ end
52
+ return session_set
53
+ end
54
+
55
+
56
+ def facebook_params
57
+ @facebook_params ||= verified_facebook_params
58
+ end
59
+
60
+ # Redirects the top window to the given url if the content is in an iframe, otherwise performs
61
+ # a normal redirect_to call.
62
+ def top_redirect_to(*args)
63
+ if request_is_facebook_iframe?
64
+ @redirect_url = url_for(*args)
65
+ render :layout => false, :inline => <<-HTML
66
+ <html><head>
67
+ <script type="text/javascript">
68
+ window.top.location.href = <%= @redirect_url.to_json -%>;
69
+ </script>
70
+ <noscript>
71
+ <meta http-equiv="refresh" content="0;url=<%=h @redirect_url %>" />
72
+ <meta http-equiv="window-target" content="_top" />
73
+ </noscript>
74
+ </head></html>
75
+ HTML
76
+ else
77
+ redirect_to(*args)
78
+ end
79
+ end
80
+
81
+ def redirect_to(*args)
82
+ if request_is_for_a_facebook_canvas? and !request_is_facebook_tab?
83
+ render :text => fbml_redirect_tag(*args)
84
+ else
85
+ super
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def session_already_secured?
92
+ (@facebook_session = session[:facebook_session]) && session[:facebook_session].secured? if valid_session_key_in_session?
93
+ end
94
+
95
+ def user_has_deauthorized_application?
96
+ # if we're inside the facebook session and there is no session key,
97
+ # that means the user revoked our access
98
+ # we don't want to keep using the old expired key from the cookie.
99
+ request_comes_from_facebook? and params[:fb_sig_session_key].blank?
100
+ end
101
+
102
+ def clear_facebook_session_information
103
+ session[:facebook_session] = nil
104
+ @facebook_session=nil
105
+ end
106
+
107
+ def valid_session_key_in_session?
108
+ #before we access the facebook_params, make sure we have the parameters
109
+ #otherwise we will blow up trying to access the secure parameters
110
+ if user_has_deauthorized_application?
111
+ clear_facebook_session_information
112
+ false
113
+ else
114
+ !session[:facebook_session].blank? && (params[:fb_sig_session_key].blank? || session[:facebook_session].session_key == facebook_params[:session_key])
115
+ end
116
+ end
117
+
118
+ def clear_fb_cookies!
119
+ domain_cookie_tag = "base_domain_#{Facebooker.api_key}"
120
+ cookie_domain = ".#{cookies[domain_cookie_tag]}" if cookies[domain_cookie_tag]
121
+ fb_cookie_names.each {|name| cookies.delete(name, :domain=>cookie_domain)}
122
+ cookies.delete Facebooker.api_key
123
+ end
124
+
125
+ def fb_cookie_prefix
126
+ Facebooker.api_key+"_"
127
+ end
128
+
129
+ def fb_cookie_names
130
+ fb_cookie_names = cookies.keys.select{|k| k.starts_with?(fb_cookie_prefix)}
131
+ end
132
+
133
+ def secure_with_cookies!
134
+ parsed = {}
135
+
136
+ fb_cookie_names.each { |key| parsed[key[fb_cookie_prefix.size,key.size]] = cookies[key] }
137
+
138
+ #returning gracefully if the cookies aren't set or have expired
139
+ return unless parsed['session_key'] && parsed['user'] && parsed['expires'] && parsed['ss']
140
+ return unless Time.at(parsed['expires'].to_s.to_f) > Time.now || (parsed['expires'] == "0")
141
+ #if we have the unexpired cookies, we'll throw an exception if the sig doesn't verify
142
+ verify_signature(parsed,cookies[Facebooker.api_key])
143
+
144
+ @facebook_session = new_facebook_session
145
+ @facebook_session.secure_with!(parsed['session_key'],parsed['user'],parsed['expires'],parsed['ss'])
146
+ @facebook_session
147
+ end
148
+
149
+ def secure_with_token!
150
+ if params['auth_token']
151
+ @facebook_session = new_facebook_session
152
+ @facebook_session.auth_token = params['auth_token']
153
+ @facebook_session.secure!
154
+ @facebook_session
155
+ end
156
+ end
157
+
158
+ def secure_with_session_secret!
159
+ if params['auth_token']
160
+ @facebook_session = new_facebook_session
161
+ @facebook_session.auth_token = params['auth_token']
162
+ @facebook_session.secure_with_session_secret!
163
+ @facebook_session
164
+ end
165
+ end
166
+
167
+ def secure_with_facebook_params!
168
+ return unless request_comes_from_facebook?
169
+
170
+ if ['user', 'session_key'].all? {|element| facebook_params[element]}
171
+ @facebook_session = new_facebook_session
172
+ @facebook_session.secure_with!(facebook_params['session_key'], facebook_params['user'], facebook_params['expires'])
173
+ @facebook_session
174
+ end
175
+ end
176
+
177
+ #override to specify where the user should be sent after logging in
178
+ def after_facebook_login_url
179
+ nil
180
+ end
181
+
182
+ def default_after_facebook_login_url
183
+ url_for(:only_path => false, :overwrite_params => {})
184
+ end
185
+
186
+ def create_new_facebook_session_and_redirect!
187
+ session[:facebook_session] = new_facebook_session
188
+ next_url = after_facebook_login_url || default_after_facebook_login_url
189
+ top_redirect_to session[:facebook_session].login_url({:next => next_url}) unless @installation_required
190
+ false
191
+ end
192
+
193
+ def new_facebook_session
194
+ Facebooker::Session.create(Facebooker.api_key, Facebooker.secret_key)
195
+ end
196
+
197
+ def capture_facebook_friends_if_available!
198
+ return unless request_comes_from_facebook?
199
+ if friends = facebook_params['friends']
200
+ facebook_session.user.friends = friends.map do |friend_uid|
201
+ User.new(friend_uid, facebook_session)
202
+ end
203
+ end
204
+ end
205
+
206
+ def blank?(value)
207
+ (value == '0' || value.nil? || value == '')
208
+ end
209
+
210
+ def verified_facebook_params
211
+ facebook_sig_params = params.inject({}) do |collection, pair|
212
+ collection[pair.first.sub(/^fb_sig_/, '')] = pair.last if pair.first[0,7] == 'fb_sig_'
213
+ collection
214
+ end
215
+ verify_signature(facebook_sig_params,params['fb_sig'])
216
+
217
+ facebook_sig_params.inject(HashWithIndifferentAccess.new) do |collection, pair|
218
+ collection[pair.first] = facebook_parameter_conversions[pair.first].call(pair.last)
219
+ collection
220
+ end
221
+ end
222
+
223
+ def earliest_valid_session
224
+ 48.hours.ago
225
+ end
226
+
227
+ def verify_signature(facebook_sig_params,expected_signature)
228
+ # Don't verify the signature if rack has already done so.
229
+ if ::Rails.version >= "2.3"
230
+ return if ActionController::Dispatcher.middleware.include? Rack::Facebook
231
+ end
232
+ raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
233
+ actual_sig = Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
234
+ raise Facebooker::Session::IncorrectSignature if actual_sig != expected_signature
235
+ raise Facebooker::Session::SignatureTooOld if facebook_sig_params['time'] && Time.at(facebook_sig_params['time'].to_f) < earliest_valid_session
236
+ true
237
+ end
238
+
239
+ def facebook_parameter_conversions
240
+ @facebook_parameter_conversions ||= Hash.new do |hash, key|
241
+ lambda{|value| value}
242
+ end.merge(
243
+ 'time' => lambda{|value| Time.at(value.to_f)},
244
+ 'in_canvas' => lambda{|value| !blank?(value)},
245
+ 'added' => lambda{|value| !blank?(value)},
246
+ 'expires' => lambda{|value| blank?(value) ? nil : Time.at(value.to_f)},
247
+ 'friends' => lambda{|value| value.split(/,/)}
248
+ )
249
+ end
250
+
251
+ def fbml_redirect_tag(url)
252
+ "<fb:redirect url=\"#{url_for(url)}\" />"
253
+ end
254
+
255
+ def request_comes_from_facebook?
256
+ request_is_for_a_facebook_canvas? || request_is_facebook_ajax? || request_is_fb_ping?
257
+ end
258
+
259
+ def request_is_fb_ping?
260
+ !params['fb_sig'].blank?
261
+ end
262
+
263
+ def request_is_for_a_facebook_canvas?
264
+ !params['fb_sig_in_canvas'].blank?
265
+ end
266
+
267
+ def request_is_facebook_tab?
268
+ !params["fb_sig_in_profile_tab"].blank?
269
+ end
270
+
271
+ def request_is_facebook_iframe?
272
+ !params["fb_sig_in_iframe"].blank?
273
+ end
274
+
275
+ def request_is_facebook_ajax?
276
+ one_or_true(params["fb_sig_is_mockajax"]) || one_or_true(params["fb_sig_is_ajax"])
277
+ end
278
+
279
+ def xml_http_request?
280
+ request_is_facebook_ajax? || super
281
+ end
282
+
283
+ def application_is_installed?
284
+ facebook_params['added']
285
+ end
286
+
287
+ def ensure_has_status_update
288
+ has_extended_permission?("status_update") || application_needs_permission("status_update")
289
+ end
290
+ def ensure_has_photo_upload
291
+ has_extended_permission?("photo_upload") || application_needs_permission("photo_upload")
292
+ end
293
+ def ensure_has_video_upload
294
+ has_extended_permission?("video_upload") || application_needs_permission("video_upload")
295
+ end
296
+ def ensure_has_create_listing
297
+ has_extended_permission?("create_listing") || application_needs_permission("create_listing")
298
+ end
299
+
300
+ def application_needs_permission(perm)
301
+ top_redirect_to(facebook_session.permission_url(perm))
302
+ end
303
+
304
+ def has_extended_permission?(perm)
305
+ params["fb_sig_ext_perms"] and params["fb_sig_ext_perms"].include?(perm)
306
+ end
307
+
308
+ def ensure_authenticated_to_facebook
309
+ set_facebook_session || create_new_facebook_session_and_redirect!
310
+ end
311
+
312
+ def ensure_application_is_installed_by_facebook_user
313
+ @installation_required = true
314
+ returning ensure_authenticated_to_facebook && application_is_installed? do |authenticated_and_installed|
315
+ application_is_not_installed_by_facebook_user unless authenticated_and_installed
316
+ end
317
+ end
318
+
319
+ def application_is_not_installed_by_facebook_user
320
+ next_url = after_facebook_login_url || default_after_facebook_login_url
321
+ top_redirect_to session[:facebook_session].install_url({:next => next_url})
322
+ end
323
+
324
+ def set_facebook_request_format
325
+ if request_is_facebook_ajax?
326
+ request.format = :fbjs
327
+ elsif request_comes_from_facebook? && !request_is_facebook_iframe?
328
+ request.format = :fbml
329
+ end
330
+ end
331
+
332
+ def set_adapter
333
+ Facebooker.load_adapter(params) if(params[:fb_sig_api_key])
334
+ end
335
+
336
+
337
+ module ClassMethods
338
+ #
339
+ # Creates a filter which reqires a user to have already authenticated to
340
+ # Facebook before executing actions. Accepts the same optional options hash which
341
+ # before_filter and after_filter accept.
342
+ def ensure_authenticated_to_facebook(options = {})
343
+ before_filter :ensure_authenticated_to_facebook, options
344
+ end
345
+
346
+ def ensure_application_is_installed_by_facebook_user(options = {})
347
+ before_filter :ensure_application_is_installed_by_facebook_user, options
348
+ end
349
+
350
+ def request_comes_from_facebook?
351
+ request_is_for_a_facebook_canvas? || request_is_facebook_ajax?
352
+ end
353
+ end
354
+ end
355
+ end
356
+ end
@@ -0,0 +1,46 @@
1
+ require 'cucumber/rails/world'
2
+ require 'facebooker/rails/integration_session'
3
+
4
+ module Facebooker
5
+ module Rails
6
+ module Cucumber
7
+ class World < ::Cucumber::Rails::World
8
+ def open_session
9
+ session = Facebooker::Rails::IntegrationSession.new
10
+
11
+ # delegate the fixture accessors back to the test instance
12
+ extras = Module.new { attr_accessor :delegate, :test_result }
13
+ if self.class.respond_to?(:fixture_table_names)
14
+ self.class.fixture_table_names.each do |table_name|
15
+ name = table_name.tr(".", "_")
16
+ next unless respond_to?(name)
17
+ extras.__send__(:define_method, name) { |*args| delegate.send(name, *args) }
18
+ end
19
+ end
20
+
21
+ # delegate add_assertion to the test case
22
+ extras.__send__(:define_method, :add_assertion) { test_result.add_assertion }
23
+ session.extend(extras)
24
+ session.delegate = self
25
+ session.test_result = @_result
26
+
27
+ yield session if block_given?
28
+ session
29
+ end
30
+
31
+ def without_canvas
32
+ in_canvas = @integration_session.canvas
33
+ @integration_session.canvas = false
34
+ yield
35
+ @integration_session.canvas = in_canvas
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ World do
43
+ w = Facebooker::Rails::Cucumber::World.new
44
+ w.reset!
45
+ w
46
+ end
@@ -0,0 +1,28 @@
1
+ require 'facebooker/rails/cucumber/world'
2
+ require 'facebooker/mock/session'
3
+ require 'facebooker/mock/service'
4
+
5
+ Facebooker::MockService.fixture_path = File.join(RAILS_ROOT, 'features', 'support', 'facebook')
6
+
7
+ module Facebooker
8
+ class << self
9
+ # prevent Facebooker from adding canvas name as prefix to URLs
10
+ def request_for_canvas(arg)
11
+ yield
12
+ end
13
+ end
14
+
15
+ module Rails
16
+ module Controller
17
+ # prevent Facebooker from rendering fb:redirect
18
+ def redirect_to(*args)
19
+ super
20
+ end
21
+
22
+ # Return the mock session
23
+ def new_facebook_session
24
+ Facebooker::MockSession.create
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ module ::ActionController
2
+ class Base
3
+ def self.inherited_with_facebooker(subclass)
4
+ inherited_without_facebooker(subclass)
5
+ if subclass.to_s == "ApplicationController"
6
+ subclass.send(:include,Facebooker::Rails::Controller)
7
+ subclass.helper Facebooker::Rails::Helpers
8
+ end
9
+ end
10
+ class << self
11
+ alias_method_chain :inherited, :facebooker
12
+ end
13
+ end
14
+ end
15
+
16
+
17
+ # When making get requests, Facebook sends fb_sig parameters both in the query string
18
+ # and also in the post body. We want to ignore the query string ones because they are one
19
+ # request out of date
20
+ # We only do thise when there are POST parameters so that IFrame linkage still works
21
+ if Rails.version < '2.3'
22
+ class ActionController::AbstractRequest
23
+ def query_parameters_with_facebooker
24
+ if request_parameters.blank?
25
+ query_parameters_without_facebooker
26
+ else
27
+ (query_parameters_without_facebooker||{}).reject {|key,value| key.to_s =~ /^fb_sig/}
28
+ end
29
+ end
30
+
31
+ alias_method_chain :query_parameters, :facebooker
32
+ end
33
+ else
34
+ class ActionController::Request
35
+ def query_parameters_with_facebooker
36
+ if request_parameters.blank?
37
+ query_parameters_without_facebooker
38
+ else
39
+ (query_parameters_without_facebooker||{}).reject {|key,value| key.to_s =~ /^fb_sig/}
40
+ end
41
+ end
42
+
43
+ alias_method_chain :query_parameters, :facebooker
44
+ end
45
+ end
46
+
47
+ Mime::Type.register_alias "text/html", :fbml
48
+ Mime::Type.register_alias "text/javascript", :fbjs
@@ -0,0 +1,6 @@
1
+ # Somewhere in 2.3 RewindableInput was removed- rack supports it natively
2
+ require 'rack/facebook'
3
+ ActionController::Dispatcher.middleware.insert_before(
4
+ ActionController::ParamsParser,
5
+ Rack::Facebook
6
+ )
@@ -0,0 +1,15 @@
1
+ class ActionController::Routing::Route
2
+ def recognition_conditions_with_facebooker
3
+ defaults = recognition_conditions_without_facebooker
4
+ defaults << " env[:canvas] == conditions[:canvas] " if conditions[:canvas]
5
+ defaults
6
+ end
7
+ alias_method_chain :recognition_conditions, :facebooker
8
+ end
9
+
10
+ # We turn off route optimization to make named routes use our code for figuring out if they should go to the session
11
+ ActionController::Base::optimise_named_routes = false
12
+
13
+ # pull :canvas=> into env in routing to allow for conditions
14
+ ActionController::Routing::RouteSet.send :include, Facebooker::Rails::Routing::RouteSetExtensions
15
+ ActionController::Routing::RouteSet::Mapper.send :include, Facebooker::Rails::Routing::MapperExtensions
@@ -0,0 +1,112 @@
1
+ module Facebooker
2
+ module Rails
3
+ class FacebookFormBuilder < ActionView::Helpers::FormBuilder
4
+
5
+
6
+ second_param = %w(password_field file_field check_box date_select datetime_select time_select)
7
+ third_param = %w(radio_button country_select select time_zone_select)
8
+ fifth_param = %w(collection_select)
9
+
10
+ def self.create_with_offset(name,offset)
11
+ define_method name do |field,*args|
12
+ options = args[offset] || {}
13
+ build_shell(field,options) do
14
+ super
15
+ end
16
+ end
17
+ end
18
+
19
+ second_param.each do |name|
20
+ create_with_offset(name,0)
21
+ end
22
+ third_param.each do |name|
23
+ create_with_offset(name,1)
24
+ end
25
+ fifth_param.each do |name|
26
+ create_with_offset(name,3)
27
+ end
28
+
29
+ def build_shell(field,options)
30
+ @template.content_tag "fb:editor-custom", :label=>label_for(field,options) do
31
+ yield
32
+ end
33
+ end
34
+
35
+ def label_for(field,options)
36
+ options[:label] || field.to_s.humanize
37
+ end
38
+
39
+ def text(string,options={})
40
+ @template.content_tag "fb:editor-custom",string, :label=>label_for("",options)
41
+ end
42
+
43
+
44
+ def text_field(method, options = {})
45
+ options[:label] ||= label_for(method,options)
46
+ add_default_name_and_id(options,method)
47
+ options["value"] ||= value_before_type_cast(object,method)
48
+ @template.content_tag("fb:editor-text","",options)
49
+ end
50
+
51
+
52
+ def text_area(method, options = {})
53
+ options[:label] ||= label_for(method,options)
54
+ add_default_name_and_id(options,method)
55
+ @template.content_tag("fb:editor-textarea",value_before_type_cast(object,method),options)
56
+ end
57
+
58
+ #
59
+ # Build a text input area that uses typeahed
60
+ # options are like collection_select
61
+ def collection_typeahead(method,collection,value_method,text_method,options={})
62
+ build_shell(method,options) do
63
+ collection_typeahead_internal(method,collection,value_method,text_method,options)
64
+ end
65
+ end
66
+
67
+ def collection_typeahead_internal(method,collection,value_method,text_method,options={})
68
+ option_values = collection.map do |item|
69
+ value=item.send(value_method)
70
+ text=item.send(text_method)
71
+ @template.content_tag "fb:typeahead-option",text,:value=>value
72
+ end.join
73
+ add_default_name_and_id(options,method)
74
+ options["value"] ||= value_before_type_cast(object,method)
75
+ @template.content_tag("fb:typeahead-input",option_values,options)
76
+ end
77
+
78
+ def value_before_type_cast(object,method)
79
+ unless object.nil?
80
+ method_name = method.to_s
81
+ object.respond_to?(method_name + "_before_type_cast") ?
82
+ object.send(method_name + "_before_type_cast") :
83
+ object.send(method_name)
84
+ end
85
+ end
86
+
87
+ def multi_friend_input(options={})
88
+ build_shell(:friends,options) do
89
+ @template.content_tag("fb:multi-friend-input","",options)
90
+ end
91
+ end
92
+
93
+ def buttons(*names)
94
+ buttons=names.map do |name|
95
+ create_button(name)
96
+ end.join
97
+
98
+ @template.content_tag "fb:editor-buttonset",buttons
99
+ end
100
+
101
+ def create_button(name)
102
+ @template.content_tag("fb:editor-button","",:value=>name,:name=>"commit")
103
+ end
104
+
105
+ def add_default_name_and_id(options,method)
106
+ options[:name] ||= "#{object.class.name.underscore}[#{method}]"
107
+ options[:id] ||= "#{object.class.name.underscore}_#{method}"
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,22 @@
1
+ class ActionController::Base
2
+ def rescues_path_with_facebooker(template_name)
3
+ t = "#{RAILS_ROOT}/vendor/plugins/facebooker/templates/#{template_name}.erb"
4
+ if pretty_facebook_errors? && File.exist?(t)
5
+ t
6
+ else
7
+ rescues_path_without_facebooker(template_name)
8
+ end
9
+ end
10
+ alias_method_chain :rescues_path, :facebooker
11
+
12
+ def response_code_for_rescue_with_facebooker(exception)
13
+ pretty_facebook_errors? ? 200 : response_code_for_rescue_without_facebooker(exception)
14
+ end
15
+ alias_method_chain :response_code_for_rescue, :facebooker
16
+
17
+
18
+ def pretty_facebook_errors?
19
+ Facebooker.facebooker_config['pretty_errors'] ||
20
+ (Facebooker.facebooker_config['pretty_errors'].nil? && RAILS_ENV=="development")
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ module ::ActionController
2
+ class AbstractRequest
3
+ include Facebooker::Rails::BackwardsCompatibleParamChecks
4
+
5
+ def request_method_with_facebooker
6
+ if parameters[:_method].blank?
7
+ if %w{GET HEAD}.include?(parameters[:fb_sig_request_method])
8
+ parameters[:_method] = parameters[:fb_sig_request_method]
9
+ end
10
+ end
11
+ request_method_without_facebooker
12
+ end
13
+
14
+ if new.methods.include?("request_method")
15
+ alias_method_chain :request_method, :facebooker
16
+ end
17
+
18
+ def xml_http_request_with_facebooker?
19
+ one_or_true(parameters["fb_sig_is_mockajax"]) ||
20
+ one_or_true(parameters["fb_sig_is_ajax"]) ||
21
+ xml_http_request_without_facebooker?
22
+ end
23
+ alias_method_chain :xml_http_request?, :facebooker
24
+ # we have to re-alias xhr? since it was pointing to the old method
25
+ alias :xhr? :xml_http_request?
26
+
27
+ end
28
+ end