djanowski-facebooker 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. data/CHANGELOG.txt +0 -0
  2. data/COPYING +19 -0
  3. data/History.txt +16 -0
  4. data/Manifest.txt +110 -0
  5. data/README +46 -0
  6. data/README.txt +81 -0
  7. data/Rakefile +76 -0
  8. data/TODO.txt +10 -0
  9. data/generators/facebook/facebook_generator.rb +14 -0
  10. data/generators/facebook/templates/config/facebooker.yml +41 -0
  11. data/generators/facebook/templates/public/javascripts/facebooker.js +106 -0
  12. data/generators/facebook_controller/USAGE +33 -0
  13. data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
  14. data/generators/facebook_controller/templates/controller.rb +7 -0
  15. data/generators/facebook_controller/templates/functional_test.rb +11 -0
  16. data/generators/facebook_controller/templates/helper.rb +2 -0
  17. data/generators/facebook_controller/templates/view.fbml.erb +2 -0
  18. data/generators/facebook_controller/templates/view.html.erb +2 -0
  19. data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
  20. data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
  21. data/generators/facebook_publisher/templates/publisher.rb +3 -0
  22. data/generators/facebook_scaffold/USAGE +27 -0
  23. data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
  24. data/generators/facebook_scaffold/templates/controller.rb +93 -0
  25. data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
  26. data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
  27. data/generators/facebook_scaffold/templates/helper.rb +2 -0
  28. data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
  29. data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
  30. data/generators/facebook_scaffold/templates/style.css +74 -0
  31. data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
  32. data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
  33. data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
  34. data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
  35. data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
  36. data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
  37. data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
  38. data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
  39. data/generators/publisher/publisher_generator.rb +14 -0
  40. data/init.rb +54 -0
  41. data/install.rb +12 -0
  42. data/lib/facebooker/adapters/adapter_base.rb +87 -0
  43. data/lib/facebooker/adapters/bebo_adapter.rb +73 -0
  44. data/lib/facebooker/adapters/facebook_adapter.rb +48 -0
  45. data/lib/facebooker/admin.rb +28 -0
  46. data/lib/facebooker/batch_request.rb +44 -0
  47. data/lib/facebooker/data.rb +57 -0
  48. data/lib/facebooker/feed.rb +78 -0
  49. data/lib/facebooker/logging.rb +51 -0
  50. data/lib/facebooker/model.rb +123 -0
  51. data/lib/facebooker/models/affiliation.rb +10 -0
  52. data/lib/facebooker/models/album.rb +11 -0
  53. data/lib/facebooker/models/applicationproperties.rb +39 -0
  54. data/lib/facebooker/models/cookie.rb +10 -0
  55. data/lib/facebooker/models/education_info.rb +11 -0
  56. data/lib/facebooker/models/event.rb +26 -0
  57. data/lib/facebooker/models/friend_list.rb +14 -0
  58. data/lib/facebooker/models/group.rb +35 -0
  59. data/lib/facebooker/models/info_item.rb +10 -0
  60. data/lib/facebooker/models/info_section.rb +10 -0
  61. data/lib/facebooker/models/location.rb +8 -0
  62. data/lib/facebooker/models/notifications.rb +17 -0
  63. data/lib/facebooker/models/page.rb +27 -0
  64. data/lib/facebooker/models/photo.rb +10 -0
  65. data/lib/facebooker/models/tag.rb +12 -0
  66. data/lib/facebooker/models/user.rb +352 -0
  67. data/lib/facebooker/models/work_info.rb +9 -0
  68. data/lib/facebooker/parser.rb +540 -0
  69. data/lib/facebooker/rails/controller.rb +246 -0
  70. data/lib/facebooker/rails/facebook_asset_path.rb +18 -0
  71. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  72. data/lib/facebooker/rails/facebook_pretty_errors.rb +14 -0
  73. data/lib/facebooker/rails/facebook_request_fix.rb +24 -0
  74. data/lib/facebooker/rails/facebook_session_handling.rb +69 -0
  75. data/lib/facebooker/rails/facebook_url_rewriting.rb +39 -0
  76. data/lib/facebooker/rails/helpers.rb +615 -0
  77. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  78. data/lib/facebooker/rails/publisher.rb +492 -0
  79. data/lib/facebooker/rails/routing.rb +49 -0
  80. data/lib/facebooker/rails/test_helpers.rb +88 -0
  81. data/lib/facebooker/rails/utilities.rb +22 -0
  82. data/lib/facebooker/server_cache.rb +24 -0
  83. data/lib/facebooker/service.rb +31 -0
  84. data/lib/facebooker/session.rb +564 -0
  85. data/lib/facebooker/version.rb +9 -0
  86. data/lib/facebooker.rb +143 -0
  87. data/lib/net/http_multipart_post.rb +123 -0
  88. data/lib/tasks/facebooker.rake +18 -0
  89. data/lib/tasks/tunnel.rake +46 -0
  90. data/rails/init.rb +1 -0
  91. data/setup.rb +1585 -0
  92. data/templates/layout.erb +24 -0
  93. data/test/adapters_test.rb +98 -0
  94. data/test/batch_request_test.rb +82 -0
  95. data/test/event_test.rb +15 -0
  96. data/test/facebook_admin_test.rb +75 -0
  97. data/test/facebook_cache_test.rb +43 -0
  98. data/test/facebook_data_test.rb +84 -0
  99. data/test/facebooker_test.rb +855 -0
  100. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  101. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  102. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  103. data/test/http_multipart_post_test.rb +54 -0
  104. data/test/logging_test.rb +43 -0
  105. data/test/model_test.rb +91 -0
  106. data/test/publisher_test.rb +436 -0
  107. data/test/rails_integration_test.rb +1126 -0
  108. data/test/session_test.rb +587 -0
  109. data/test/test_helper.rb +60 -0
  110. data/test/user_test.rb +229 -0
  111. metadata +181 -0
@@ -0,0 +1,492 @@
1
+ module Facebooker
2
+ module Rails
3
+ # ActionMailer like module for publishing Facbook messages
4
+ #
5
+ # To use, create a subclass and define methods
6
+ # Each method should start by calling send_as to specify the type of message
7
+ # Valid options are :email and :notification, :user_action, :profile, :ref
8
+ #
9
+ #
10
+ # Below is an example of each type
11
+ #
12
+ # class TestPublisher < Facebooker::Rails::Publisher
13
+ # # The new message templates are supported as well
14
+ # # First, create a method that contains your templates:
15
+ # # You may include multiple one line story templates and short story templates
16
+ # # but only one full story template
17
+ # # Your most specific template should be first
18
+ # #
19
+ # # Before using, you must register your template by calling register. For this example
20
+ # # You would call TestPublisher.register_publish_action
21
+ # # Registering the template will store the template id returned from Facebook in the
22
+ # # facebook_templates table that is created when you create your first publisher
23
+ # def publish_action_template
24
+ # one_line_story_template "{*actor*} did stuff with {*friend*}"
25
+ # one_line_story_template "{*actor*} did stuff"
26
+ # short_story_template "{*actor*} has a title {*friend*}", render(:partial=>"short_body")
27
+ # short_story_template "{*actor*} has a title", render(:partial=>"short_body")
28
+ # full_story_template "{*actor*} has a title {*friend*}", render(:partial=>"full_body")
29
+ # action_links action_link("My text {*template_var*}","{*link_url*}")
30
+ # end
31
+ #
32
+ # # To send a registered template, you need to create a method to set the data
33
+ # # The publisher will look up the template id from the facebook_templates table
34
+ # def publish_action(f)
35
+ # send_as :user_action
36
+ # from f
37
+ # data :friend=>"Mike"
38
+ # end
39
+ #
40
+ #
41
+ # # Provide a from user to send a general notification
42
+ # # if from is nil, this will send an announcement
43
+ # def notification(to,f)
44
+ # send_as :notification
45
+ # recipients to
46
+ # from f
47
+ # fbml "Not"
48
+ # end
49
+ #
50
+ # def email(to,f)
51
+ # send_as :email
52
+ # recipients to
53
+ # from f
54
+ # title "Email"
55
+ # fbml 'text'
56
+ # text fbml
57
+ # end
58
+ # # This will render the profile in /users/profile.erb
59
+ # # it will set @user to user_to_update in the template
60
+ # # The mobile profile will be rendered from the app/views/test_publisher/_mobile.erb
61
+ # # template
62
+ # def profile_update(user_to_update,user_with_session_to_use)
63
+ # send_as :profile
64
+ # from user_with_session_to_use
65
+ # to user_to_update
66
+ # profile render(:action=>"/users/profile",:assigns=>{:user=>user_to_update})
67
+ # profile_action "A string"
68
+ # mobile_profile render(:partial=>"mobile",:assigns=>{:user=>user_to_update})
69
+ # end
70
+ #
71
+ # # Update the given handle ref with the content from a
72
+ # # template
73
+ # def ref_update(user)
74
+ # send_as :ref
75
+ # from user
76
+ # fbml render(:action=>"/users/profile",:assigns=>{:user=>user_to_update})
77
+ # handle "a_ref_handle"
78
+ # end
79
+ #
80
+ #
81
+ # To send a message, use ActionMailer like semantics
82
+ # TestPublisher.deliver_action(@user)
83
+ #
84
+ # For testing, you may want to create an instance of the underlying message without sending it
85
+ # TestPublisher.create_action(@user)
86
+ # will create and return an instance of Facebooker::Feeds::Action
87
+ #
88
+ # Publisher makes many helpers available, including the linking and asset helpers
89
+ class Publisher
90
+ def initialize
91
+ @controller = PublisherController.new
92
+ end
93
+
94
+ # use facebook options everywhere
95
+ def request_comes_from_facebook?
96
+ true
97
+ end
98
+
99
+ class FacebookTemplate < ::ActiveRecord::Base
100
+
101
+
102
+ cattr_accessor :template_cache
103
+ self.template_cache = {}
104
+
105
+ def self.inspect(*args)
106
+ "FacebookTemplate"
107
+ end
108
+
109
+ def template_changed?(hash)
110
+ if respond_to?(:content_hash)
111
+ content_hash != hash
112
+ else
113
+ false
114
+ end
115
+ end
116
+
117
+ class << self
118
+
119
+ def register(klass,method)
120
+ publisher = setup_publisher(klass,method)
121
+ template_id = Facebooker::Session.create.register_template_bundle(publisher.one_line_story_templates,publisher.short_story_templates,publisher.full_story_template,publisher.action_links)
122
+ template = find_or_initialize_by_template_name(template_name(klass,method))
123
+ template.bundle_id = template_id
124
+ template.content_hash = hashed_content(klass,method) if template.respond_to?(:content_hash)
125
+ template.save!
126
+ cache(klass,method,template)
127
+ template
128
+ end
129
+
130
+ def for_class_and_method(klass,method)
131
+ find_cached(klass,method)
132
+ end
133
+ def bundle_id_for_class_and_method(klass,method)
134
+ for_class_and_method(klass,method).bundle_id
135
+ end
136
+
137
+ def cache(klass,method,template)
138
+ template_cache[template_name(klass,method)] = template
139
+ end
140
+
141
+ def clear_cache!
142
+ self.template_cache = {}
143
+ end
144
+
145
+ def find_cached(klass,method)
146
+ template_cache[template_name(klass,method)] || find_in_db(klass,method)
147
+ end
148
+
149
+ def find_in_db(klass,method)
150
+ template = find_by_template_name(template_name(klass,method))
151
+ if template and template.template_changed?(hashed_content(klass,method))
152
+ template.destroy
153
+ template = nil
154
+ end
155
+
156
+ if template.nil?
157
+ template = register(klass,method)
158
+ end
159
+ template
160
+ end
161
+
162
+ def setup_publisher(klass,method)
163
+ publisher = klass.new
164
+ publisher.send method + '_template'
165
+ publisher
166
+ end
167
+
168
+ def hashed_content(klass, method)
169
+ publisher = setup_publisher(klass,method)
170
+ Digest::MD5.hexdigest [publisher.one_line_story_templates, publisher.short_story_templates, publisher.full_story_template].to_json
171
+ end
172
+
173
+
174
+ def template_name(klass,method)
175
+ "#{klass.name}::#{method}"
176
+ end
177
+ end
178
+ end
179
+
180
+ class_inheritable_accessor :master_helper_module
181
+ attr_accessor :one_line_story_templates, :short_story_templates, :action_links
182
+
183
+ cattr_accessor :skip_registry
184
+ self.skip_registry = false
185
+
186
+
187
+ class InvalidSender < StandardError; end
188
+ class UnknownBodyType < StandardError; end
189
+ class UnspecifiedBodyType < StandardError; end
190
+ class Email
191
+ attr_accessor :title
192
+ attr_accessor :text
193
+ attr_accessor :fbml
194
+ end
195
+
196
+ class Notification
197
+ attr_accessor :fbml
198
+ end
199
+
200
+ class Profile
201
+ attr_accessor :profile
202
+ attr_accessor :profile_action
203
+ attr_accessor :mobile_profile
204
+ attr_accessor :profile_main
205
+ end
206
+ class Ref
207
+ attr_accessor :handle
208
+ attr_accessor :fbml
209
+ end
210
+ class UserAction
211
+ attr_accessor :data
212
+ attr_accessor :target_ids
213
+ attr_accessor :body_general
214
+ attr_accessor :template_id
215
+ attr_accessor :template_name
216
+
217
+ def target_ids=(val)
218
+ @target_ids = val.is_a?(Array) ? val.join(",") : val
219
+ end
220
+
221
+ end
222
+
223
+ cattr_accessor :ignore_errors
224
+ attr_accessor :_body
225
+
226
+ def recipients(*args)
227
+ if args.size==0
228
+ @recipients
229
+ else
230
+ @recipients=args.first
231
+ end
232
+ end
233
+
234
+ def from(*args)
235
+ if args.size==0
236
+ @from
237
+ else
238
+ @from=args.first
239
+ end
240
+ end
241
+
242
+
243
+ def send_as(option)
244
+ self._body=case option
245
+ when :action
246
+ Facebooker::Feed::Action.new
247
+ when :story
248
+ Facebooker::Feed::Story.new
249
+ when :templatized_action
250
+ Facebooker::Feed::TemplatizedAction.new
251
+ when :notification
252
+ Notification.new
253
+ when :email
254
+ Email.new
255
+ when :profile
256
+ Profile.new
257
+ when :ref
258
+ Ref.new
259
+ when :user_action
260
+ UserAction.new
261
+ else
262
+ raise UnknownBodyType.new("Unknown type to publish")
263
+ end
264
+ end
265
+
266
+ def full_story_template(title=nil,body=nil,params={})
267
+ if title.nil?
268
+ @full_story_template
269
+ else
270
+ @full_story_template=params.merge(:template_title=>title, :template_body=>body)
271
+ end
272
+ end
273
+
274
+ def one_line_story_template(str)
275
+ @one_line_story_templates ||= []
276
+ @one_line_story_templates << str
277
+ end
278
+
279
+ def short_story_template(title,body,params={})
280
+ @short_story_templates ||= []
281
+ @short_story_templates << params.merge(:template_title=>title, :template_body=>body)
282
+ end
283
+
284
+ def action_links(*links)
285
+ if links.blank?
286
+ @action_links
287
+ else
288
+ @action_links = links
289
+ end
290
+ end
291
+
292
+ def method_missing(name,*args)
293
+ if args.size==1 and self._body.respond_to?("#{name}=")
294
+ self._body.send("#{name}=",*args)
295
+ elsif self._body.respond_to?(name)
296
+ self._body.send(name,*args)
297
+ else
298
+ super
299
+ end
300
+ end
301
+
302
+ def image(src,target)
303
+ {:src=>image_path(src),:href=> target.respond_to?(:to_str) ? target : url_for(target)}
304
+ end
305
+
306
+ def action_link(text,target)
307
+ {:text=>text, :href=>target}
308
+ end
309
+
310
+ def requires_from_user?(from,body)
311
+ ! (announcement_notification?(from,body) or ref_update?(body) or profile_update?(body))
312
+ end
313
+
314
+ def profile_update?(body)
315
+ body.is_a?(Profile)
316
+ end
317
+
318
+ def ref_update?(body)
319
+ body.is_a?(Ref)
320
+ end
321
+
322
+ def announcement_notification?(from,body)
323
+ from.nil? and body.is_a?(Notification)
324
+ end
325
+
326
+ def send_message(method)
327
+ @recipients = @recipients.is_a?(Array) ? @recipients : [@recipients]
328
+ if from.nil? and @recipients.size==1 and requires_from_user?(from,_body)
329
+ @from = @recipients.first
330
+ end
331
+ # notifications can
332
+ # omit the from address
333
+ raise InvalidSender.new("Sender must be a Facebooker::User") unless from.is_a?(Facebooker::User) || !requires_from_user?(from,_body)
334
+ case _body
335
+ when Facebooker::Feed::TemplatizedAction,Facebooker::Feed::Action
336
+ from.publish_action(_body)
337
+ when Facebooker::Feed::Story
338
+ @recipients.each {|r| r.publish_story(_body)}
339
+ when Notification
340
+ (from.nil? ? Facebooker::Session.create : from.session).send_notification(@recipients,_body.fbml)
341
+ when Email
342
+ from.session.send_email(@recipients,
343
+ _body.title,
344
+ _body.text,
345
+ _body.fbml)
346
+ when Profile
347
+ # If recipient and from aren't the same person, create a new user object using the
348
+ # userid from recipient and the session from from
349
+ @from = Facebooker::User.new(Facebooker::User.cast_to_facebook_id(@recipients.first),Facebooker::Session.create)
350
+ @from.set_profile_fbml(_body.profile, _body.mobile_profile, _body.profile_action, _body.profile_main)
351
+ when Ref
352
+ Facebooker::Session.create.server_cache.set_ref_handle(_body.handle,_body.fbml)
353
+ when UserAction
354
+ @from.session.publish_user_action(_body.template_id,_body.data||{},_body.target_ids,_body.body_general)
355
+ else
356
+ raise UnspecifiedBodyType.new("You must specify a valid send_as")
357
+ end
358
+ end
359
+
360
+ # nodoc
361
+ # needed for actionview
362
+ def logger
363
+ RAILS_DEFAULT_LOGGER
364
+ end
365
+
366
+ # nodoc
367
+ # delegate to action view. Set up assigns and render
368
+ def render(opts)
369
+ opts = opts.dup
370
+ body = opts.delete(:assigns) || {}
371
+ initialize_template_class(body.dup.merge(:controller=>self)).render(opts)
372
+ end
373
+
374
+
375
+ def initialize_template_class(assigns)
376
+ template_root = "#{RAILS_ROOT}/app/views"
377
+ controller_root = File.join(template_root,self.class.controller_path)
378
+ #only do this on Rails 2.1
379
+ if ActionController::Base.respond_to?(:append_view_path)
380
+ # only add the view path once
381
+ ActionController::Base.append_view_path(controller_root) unless ActionController::Base.view_paths.include?(controller_root)
382
+ end
383
+ returning ActionView::Base.new([template_root,controller_root], assigns, self) do |template|
384
+ template.controller=self
385
+ template.extend(self.class.master_helper_module)
386
+ end
387
+ end
388
+
389
+
390
+ self.master_helper_module = Module.new
391
+ self.master_helper_module.module_eval do
392
+ # url_helper delegates to @controller,
393
+ # so we need to define that in the template
394
+ # we make it point to the publisher
395
+ include ActionView::Helpers::UrlHelper
396
+ include ActionView::Helpers::TextHelper
397
+ include ActionView::Helpers::TagHelper
398
+ include ActionView::Helpers::FormHelper
399
+ include ActionView::Helpers::FormTagHelper
400
+ include ActionView::Helpers::AssetTagHelper
401
+ include Facebooker::Rails::Helpers
402
+
403
+ #define this for the publisher views
404
+ def protect_against_forgery?
405
+ @paf ||= ActionController::Base.new.send(:protect_against_forgery?)
406
+ end
407
+ end
408
+ ActionController::Routing::Routes.named_routes.install(self.master_helper_module)
409
+ include self.master_helper_module
410
+ class <<self
411
+
412
+ def register_all_templates
413
+ all_templates = instance_methods.grep(/_template$/) - %w(short_story_template full_story_template one_line_story_template)
414
+ all_templates.each do |template|
415
+ template_name=template.sub(/_template$/,"")
416
+ puts "Registering #{template_name}"
417
+ send("register_"+template_name)
418
+ end
419
+ end
420
+
421
+ def method_missing(name,*args)
422
+ should_send = false
423
+ method = ''
424
+ if md = /^create_(.*)$/.match(name.to_s)
425
+ method = md[1]
426
+ elsif md = /^deliver_(.*)$/.match(name.to_s)
427
+ method = md[1]
428
+ should_send = true
429
+ elsif md = /^register_(.*)$/.match(name.to_s)
430
+ return FacebookTemplate.register(self, md[1])
431
+ else
432
+ super
433
+ end
434
+
435
+ #now create the item
436
+ (publisher=new).send(method,*args)
437
+ case publisher._body
438
+ when UserAction
439
+ publisher._body.template_name = method
440
+ publisher._body.template_id = FacebookTemplate.bundle_id_for_class_and_method(self,method)
441
+ end
442
+
443
+ should_send ? publisher.send_message(method) : publisher._body
444
+ end
445
+
446
+ def default_url_options
447
+ {:host => Facebooker.canvas_server_base + Facebooker.facebook_path_prefix}
448
+ end
449
+
450
+ def controller_path
451
+ self.to_s.underscore
452
+ end
453
+
454
+ def helper(*args)
455
+ args.each do |arg|
456
+ case arg
457
+ when Symbol,String
458
+ add_template_helper("#{arg.to_s.classify}Helper".constantize)
459
+ when Module
460
+ add_template_helper(arg)
461
+ end
462
+ end
463
+ end
464
+
465
+ def add_template_helper(helper_module) #:nodoc:
466
+ master_helper_module.send :include,helper_module
467
+ include master_helper_module
468
+ end
469
+
470
+
471
+ def inherited(child)
472
+ super
473
+ child.master_helper_module=Module.new
474
+ child.master_helper_module.__send__(:include,self.master_helper_module)
475
+ child.send(:include, child.master_helper_module)
476
+ FacebookTemplate.clear_cache!
477
+ end
478
+
479
+ end
480
+ class PublisherController
481
+ include Facebooker::Rails::Publisher.master_helper_module
482
+ include ActionController::UrlWriter
483
+
484
+ def self.default_url_options(*args)
485
+ Facebooker::Rails::Publisher.default_url_options(*args)
486
+ end
487
+
488
+ end
489
+
490
+ end
491
+ end
492
+ end
@@ -0,0 +1,49 @@
1
+ module Facebooker
2
+ module Rails
3
+ module Routing
4
+ module RouteSetExtensions
5
+ def self.included(base)
6
+ base.alias_method_chain :extract_request_environment, :facebooker
7
+ end
8
+
9
+ def extract_request_environment_with_facebooker(request)
10
+ env = extract_request_environment_without_facebooker(request)
11
+ env.merge :canvas => (request.parameters[:fb_sig_in_canvas]=="1")
12
+ end
13
+ end
14
+ module MapperExtensions
15
+
16
+ # Generates pseudo-resource routes. Since everything is a POST, routes can't be identified
17
+ # using HTTP verbs. Therefore, the action is appended to the beginning of each named route,
18
+ # except for index.
19
+ #
20
+ # Example:
21
+ # map.facebook_resources :profiles
22
+ #
23
+ # Generates the following routes:
24
+ #
25
+ # new_profile POST /profiles/new {:controller=>"profiles", :action=>"new"}
26
+ # profiles POST /profiles/index {:controller=>"profiles", :action=>"index"}
27
+ # show_profile POST /profiles/:id/show {:controller=>"profiles", :action=>"show"}
28
+ # create_profile POST /profiles/create {:controller=>"profiles", :action=>"create"}
29
+ # edit_profile POST /profiles/:id/edit {:controller=>"profiles", :action=>"edit"}
30
+ # update_profile POST /profiles/:id/update {:controller=>"profiles", :action=>"update"}
31
+ # destroy_profile POST /profiles/:id/destroy {:controller=>"profiles", :action=>"destroy"}
32
+ #
33
+ def facebook_resources(name_sym)
34
+ name = name_sym.to_s
35
+
36
+ with_options :controller => name, :conditions => { :method => :post } do |map|
37
+ map.named_route("new_#{name.singularize}", "#{name}/new", :action => 'new')
38
+ map.named_route(name, "#{name}/index", :action => 'index')
39
+ map.named_route("show_#{name.singularize}", "#{name}/:id/show", :action => 'show', :id => /\d+/)
40
+ map.named_route("create_#{name.singularize}", "#{name}/create", :action => 'create')
41
+ map.named_route("edit_#{name.singularize}", "#{name}/:id/edit", :action => 'edit', :id => /\d+/)
42
+ map.named_route("update_#{name.singularize}", "#{name}/:id/update", :action => 'update', :id => /\d+/)
43
+ map.named_route("destroy_#{name.singularize}", "#{name}/:id/destroy", :action => 'destroy', :id => /\d+/)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,88 @@
1
+ module Facebooker
2
+ module Rails
3
+ module TestHelpers
4
+ def assert_facebook_redirect_to(url)
5
+ assert_response :success
6
+ assert_not_nil facebook_redirect_url
7
+ assert_equal url, facebook_redirect_url
8
+ end
9
+
10
+ def follow_facebook_redirect!
11
+ facebook_post facebook_redirect_url
12
+ end
13
+
14
+ def facebook_get(path,params={})
15
+ facebook_verb(:get,path,params)
16
+ end
17
+
18
+ def facebook_post(path,params={})
19
+ facebook_verb(:post,path,params)
20
+ end
21
+
22
+ def facebook_put(path,params={})
23
+ facebook_verb(:put,path,params)
24
+ end
25
+ def facebook_delete(path,params={})
26
+ facebook_verb(:delete,path,params)
27
+ end
28
+
29
+ def facebook_verb(verb,path, params={})
30
+ params = default_facebook_parameters.update(params)
31
+ params.merge!(:fb_sig => generate_signature(facebook_params(params).stringify_keys))
32
+
33
+ params = params.update(:canvas => true).update(params)
34
+ send verb, path, params
35
+ end
36
+
37
+ def facebook_post(path, params={}, fb_params=facebook_parameters)
38
+ params = fb_params.merge(:canvas => true).merge(params)
39
+ post path, params
40
+ end
41
+
42
+ def facebook_parameters(overrides=nil)
43
+ overrides ||= {}
44
+ params = default_facebook_parameters.merge(overrides)
45
+ params.merge(:fb_sig => generate_signature(params.stringify_keys))
46
+ end
47
+
48
+ private
49
+
50
+ def default_facebook_parameters
51
+ {
52
+ :fb_sig_added => "1",
53
+ :fb_sig_session_key => "facebook_session_key",
54
+ :fb_sig_user => "1234",
55
+ :fb_sig_expires => "0",
56
+ :fb_sig_in_canvas => "1",
57
+ :fb_sig_time => Time.now.to_f
58
+ }
59
+ end
60
+
61
+ def facebook_params(params)
62
+ params.inject({}) do |fb_params, pair|
63
+ unless pair.first.to_s.match(/^fb_sig_/).nil?
64
+ fb_params[pair.first] = pair.last
65
+ end
66
+ fb_params
67
+ end
68
+ end
69
+
70
+ def facebook_redirect_url
71
+ match = @response.body.match(/<fb:redirect url="([^"]+)"/)
72
+ match.nil? ? nil : match.captures[0]
73
+ end
74
+
75
+ def generate_signature(facebook_params)
76
+ facebook_sig_params = facebook_params.inject({}) do |collection, pair|
77
+ collection[pair.first.sub(/^fb_sig_/, '')] = pair.last
78
+ collection
79
+ end
80
+
81
+ raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
82
+ Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
83
+ end
84
+
85
+ end
86
+ end
87
+ end
88
+
@@ -0,0 +1,22 @@
1
+ module Facebooker
2
+ module Rails
3
+ class Utilities
4
+ class << self
5
+ def refresh_all_images(session)
6
+ Dir.glob(File.join(RAILS_ROOT,"public","images","*.{png,jpg,gif}")).each do |img|
7
+ refresh_image(session,img)
8
+ end
9
+ end
10
+
11
+ def refresh_image(session,full_path)
12
+ basename=File.basename(full_path)
13
+ base_path=ActionController::Base.asset_host
14
+ base_path += "/" unless base_path.ends_with?("/")
15
+ image_path=base_path+"images/#{basename}"
16
+ puts "refreshing: #{image_path}"
17
+ session.server_cache.refresh_img_src(image_path)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ module Facebooker
2
+ class ServerCache
3
+ def initialize(session)
4
+ @session = session
5
+ end
6
+
7
+ #
8
+ # Stores an FBML reference on the server for use
9
+ # across multiple users in FBML
10
+ def set_ref_handle(handle_name, fbml_source)
11
+ (@session.post 'facebook.fbml.setRefHandle', {:handle => handle_name, :fbml => fbml_source},false) == '1'
12
+ end
13
+
14
+ ##
15
+ # Fetches and re-caches the content stored at the given URL, for use in a fb:ref FBML tag.
16
+ def refresh_ref_url(url)
17
+ (@session.post 'facebook.fbml.refreshRefUrl', {:url => url},false) == '1'
18
+ end
19
+
20
+ def refresh_img_src(url)
21
+ (@session.post 'facebook.fbml.refreshImgSrc', {:url => url},false) == '1'
22
+ end
23
+ end
24
+ end