taweili-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/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 +497 -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 +337 -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 +30 -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 +780 -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 +554 -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 +606 -0
  102. data/lib/facebooker/version.rb +9 -0
  103. data/lib/facebooker.rb +180 -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,38 @@
1
+ require 'action_controller/integration'
2
+
3
+ class Facebooker::Rails::IntegrationSession < ActionController::Integration::Session
4
+ include Facebooker::Rails::TestHelpers
5
+ attr_accessor :default_request_params, :canvas
6
+
7
+ def process(method, path, parameters = nil, headers = nil)
8
+ if canvas
9
+ parameters = facebook_params(@default_request_params.merge(parameters || {}))
10
+ end
11
+ super method, path, parameters, headers
12
+ end
13
+
14
+ def reset!
15
+ self.default_request_params = {:fb_sig_in_canvas => '1'}.with_indifferent_access
16
+ self.canvas = true
17
+ super
18
+ end
19
+
20
+ def get(path, parameters = nil, headers = nil)
21
+ if canvas
22
+ post path, (parameters || {}).merge('fb_sig_request_method' => 'GET'), headers
23
+ else
24
+ super path, parameters, headers
25
+ end
26
+ end
27
+
28
+ %w(put delete).each do |method|
29
+ define_method method do |*args|
30
+ if canvas
31
+ path, parameters, headers = *args
32
+ post path, (parameters || {}).merge('_method' => method.upcase), headers
33
+ else
34
+ super *args
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ module Facebooker
2
+ module Rails
3
+ module ProfilePublisherExtensions
4
+
5
+ ##
6
+ # returns true if Facebook is requesting the interface for a profile publisher
7
+ def wants_interface?
8
+ params[:method] == "publisher_getInterface"
9
+ end
10
+
11
+ ##
12
+ # render the interface for a publisher.
13
+ # fbml is the content in string form. Use render_to_string to get the content from a template
14
+ # publish_enabled controlls whether the post form is active by default. If it isn't, you'll need to use fbjs to activate it
15
+ # comment_enabled controls whether to include a comment box
16
+ def render_publisher_interface(fbml,publish_enabled=true,comment_enabled=false)
17
+ render :json=>{:content=>{:fbml=>fbml,:publishEnabled=>publish_enabled,:commentEnabled=>comment_enabled},
18
+ :method=>"publisher_getInterface"}
19
+ end
20
+
21
+ # render an error while publishing the template
22
+ # This can be used for validation errors
23
+ def render_publisher_error(title,body)
24
+ render :json=>{:errorCode=>1,:errorTitle=>title,:errorMessage=>body}.to_json
25
+ end
26
+
27
+ # render the response for a feed. This takes a user_action object like those returned from the Rails Publisher
28
+ # For instance, AttackPublisher.create_attack(@attack)
29
+ # The template must have been registered previously
30
+ def render_publisher_response(user_action)
31
+ render :json=>{:content=> {
32
+ :feed=>{
33
+ :template_id=>user_action.template_id,
34
+ :template_data=>user_action.data
35
+ }
36
+ },
37
+ :method=>"publisher_getFeedStory"
38
+ }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,554 @@
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
+ # story_size SHORT # or ONE_LINE or FULL
38
+ # data :friend=>"Mike"
39
+ # end
40
+ #
41
+ #
42
+ # # Provide a from user to send a general notification
43
+ # # if from is nil, this will send an announcement
44
+ # def notification(to,f)
45
+ # send_as :notification
46
+ # recipients to
47
+ # from f
48
+ # fbml "Not"
49
+ # end
50
+ #
51
+ # def email(to,f)
52
+ # send_as :email
53
+ # recipients to
54
+ # from f
55
+ # title "Email"
56
+ # fbml 'text'
57
+ # text fbml
58
+ # end
59
+ # # This will render the profile in /users/profile.fbml.erb
60
+ # # it will set @user to user_to_update in the template
61
+ # # The mobile profile will be rendered from the app/views/test_publisher/_mobile.erb
62
+ # # template
63
+ # def profile_update(user_to_update,user_with_session_to_use)
64
+ # send_as :profile
65
+ # from user_with_session_to_use
66
+ # recipients user_to_update
67
+ # profile render(:file=>"users/profile.fbml.erb",:assigns=>{:user=>user_to_update})
68
+ # profile_action "A string"
69
+ # mobile_profile render(:partial=>"mobile",:assigns=>{:user=>user_to_update})
70
+ # end
71
+ #
72
+ # # Update the given handle ref with the content from a
73
+ # # template
74
+ # def ref_update(user)
75
+ # send_as :ref
76
+ # from user
77
+ # fbml render(:file=>"users/profile",:assigns=>{:user=>user_to_update})
78
+ # handle "a_ref_handle"
79
+ # end
80
+ #
81
+ #
82
+ # To send a message, use ActionMailer like semantics
83
+ # TestPublisher.deliver_action(@user)
84
+ #
85
+ # For testing, you may want to create an instance of the underlying message without sending it
86
+ # TestPublisher.create_action(@user)
87
+ # will create and return an instance of Facebooker::Feeds::Action
88
+ #
89
+ # Publisher makes many helpers available, including the linking and asset helpers
90
+ class Publisher
91
+
92
+ #story sizes from the Facebooker API
93
+ ONE_LINE=1
94
+ SHORT=2
95
+ FULL=4
96
+
97
+ def initialize
98
+ @from = nil
99
+ @full_story_template = nil
100
+ @recipients = nil
101
+ @controller = PublisherController.new(self)
102
+ end
103
+
104
+ def default_url_options
105
+ {:host => Facebooker.canvas_server_base + Facebooker.facebook_path_prefix}
106
+ end
107
+
108
+ # use facebook options everywhere
109
+ def request_comes_from_facebook?
110
+ true
111
+ end
112
+
113
+ def self.bundle_id_for_method(method_name)
114
+ FacebookTemplate.bundle_id_for_class_and_method(self,method_name)
115
+ end
116
+
117
+ class FacebookTemplate < ::ActiveRecord::Base
118
+ cattr_accessor :template_cache
119
+ self.template_cache = {}
120
+
121
+ def self.inspect(*args)
122
+ "FacebookTemplate"
123
+ end
124
+
125
+ def template_changed?(hash)
126
+ if respond_to?(:content_hash)
127
+ content_hash != hash
128
+ else
129
+ false
130
+ end
131
+ end
132
+
133
+
134
+
135
+ class << self
136
+
137
+ def register(klass,method)
138
+ publisher = setup_publisher(klass,method)
139
+ template_id = Facebooker::Session.create.register_template_bundle(publisher.one_line_story_templates,publisher.short_story_templates,publisher.full_story_template,publisher.action_links)
140
+ template = find_or_initialize_by_template_name(template_name(klass,method))
141
+ template.bundle_id = template_id
142
+ template.content_hash = hashed_content(klass,method) if template.respond_to?(:content_hash)
143
+ template.save!
144
+ cache(klass,method,template)
145
+ template
146
+ end
147
+
148
+ def for_class_and_method(klass,method)
149
+ find_cached(klass,method)
150
+ end
151
+ def bundle_id_for_class_and_method(klass,method)
152
+ for_class_and_method(klass,method).bundle_id
153
+ end
154
+
155
+ def cache(klass,method,template)
156
+ template_cache[template_name(klass,method)] = template
157
+ end
158
+
159
+ def clear_cache!
160
+ self.template_cache = {}
161
+ end
162
+
163
+ def find_cached(klass,method)
164
+ template_cache[template_name(klass,method)] || find_in_db(klass,method)
165
+ end
166
+
167
+ def find_in_db(klass,method)
168
+ template = find_by_template_name(template_name(klass,method))
169
+ if template and template.template_changed?(hashed_content(klass,method))
170
+ template.destroy
171
+ template = nil
172
+ end
173
+
174
+ if template.nil?
175
+ template = register(klass,method)
176
+ end
177
+ template
178
+ end
179
+
180
+ def setup_publisher(klass,method)
181
+ publisher = klass.new
182
+ publisher.send method + '_template'
183
+ publisher
184
+ end
185
+
186
+ def hashed_content(klass, method)
187
+ publisher = setup_publisher(klass,method)
188
+ # sort the Hash elements (in the short_story and full_story) before generating MD5
189
+ Digest::MD5.hexdigest [publisher.one_line_story_templates,
190
+ (publisher.short_story_templates and publisher.short_story_templates.collect{|ss| ss.to_a.sort_by{|e| e[0].to_s}}),
191
+ (publisher.full_story_template and publisher.full_story_template.to_a.sort_by{|e| e[0].to_s})
192
+ ].to_json
193
+ end
194
+
195
+ def template_name(klass,method)
196
+ "#{klass.name}::#{method}"
197
+ end
198
+ end
199
+ end
200
+
201
+ class_inheritable_accessor :master_helper_module
202
+ attr_accessor :one_line_story_templates, :short_story_templates
203
+ attr_writer :action_links
204
+
205
+ cattr_accessor :skip_registry
206
+ self.skip_registry = false
207
+
208
+
209
+ class InvalidSender < StandardError; end
210
+ class UnknownBodyType < StandardError; end
211
+ class UnspecifiedBodyType < StandardError; end
212
+ class Email
213
+ attr_accessor :title
214
+ attr_accessor :text
215
+ attr_accessor :fbml
216
+ end
217
+
218
+ class Notification
219
+ attr_accessor :fbml
220
+ end
221
+
222
+ class Profile
223
+ attr_accessor :profile
224
+ attr_accessor :profile_action
225
+ attr_accessor :mobile_profile
226
+ attr_accessor :profile_main
227
+ end
228
+ class Ref
229
+ attr_accessor :handle
230
+ attr_accessor :fbml
231
+ end
232
+ class UserAction
233
+ attr_accessor :data
234
+ attr_reader :target_ids
235
+ attr_accessor :body_general
236
+ attr_accessor :template_id
237
+ attr_accessor :template_name
238
+ attr_accessor :story_size
239
+
240
+ def target_ids=(val)
241
+ @target_ids = val.is_a?(Array) ? val.join(",") : val
242
+ end
243
+
244
+ def data_hash
245
+ data||{}
246
+ end
247
+ end
248
+
249
+ cattr_accessor :ignore_errors
250
+ attr_accessor :_body
251
+
252
+ def recipients(*args)
253
+ if args.size==0
254
+ @recipients
255
+ else
256
+ @recipients=args.first
257
+ end
258
+ end
259
+
260
+ def from(*args)
261
+ if args.size==0
262
+ @from
263
+ else
264
+ @from=args.first
265
+ end
266
+ end
267
+
268
+
269
+ def send_as(option)
270
+ self._body=case option
271
+ when :action
272
+ Facebooker::Feed::Action.new
273
+ when :story
274
+ Facebooker::Feed::Story.new
275
+ when :templatized_action
276
+ Facebooker::Feed::TemplatizedAction.new
277
+ when :notification
278
+ Notification.new
279
+ when :email
280
+ Email.new
281
+ when :profile
282
+ Profile.new
283
+ when :ref
284
+ Ref.new
285
+ when :user_action
286
+ UserAction.new
287
+ else
288
+ raise UnknownBodyType.new("Unknown type to publish")
289
+ end
290
+ end
291
+
292
+ def full_story_template(title=nil,body=nil,params={})
293
+ if title.nil?
294
+ @full_story_template
295
+ else
296
+ @full_story_template=params.merge(:template_title=>title, :template_body=>body)
297
+ end
298
+ end
299
+
300
+ def one_line_story_template(str)
301
+ @one_line_story_templates ||= []
302
+ @one_line_story_templates << str
303
+ end
304
+
305
+ def short_story_template(title,body,params={})
306
+ @short_story_templates ||= []
307
+ @short_story_templates << params.merge(:template_title=>title, :template_body=>body)
308
+ end
309
+
310
+ def action_links(*links)
311
+ if links.blank?
312
+ @action_links
313
+ else
314
+ @action_links = links
315
+ end
316
+ end
317
+
318
+ def method_missing(name,*args)
319
+ if args.size==1 and self._body.respond_to?("#{name}=")
320
+ self._body.send("#{name}=",*args)
321
+ elsif self._body.respond_to?(name)
322
+ self._body.send(name,*args)
323
+ else
324
+ super
325
+ end
326
+ end
327
+
328
+ # work around the fact that facebook cares about the order of the keys in the hash
329
+ class ImageHolder
330
+ attr_accessor :src,:href
331
+ def initialize(src,href)
332
+ self.src=src
333
+ self.href=href
334
+ end
335
+
336
+ def ==(other)
337
+ self.src == other.src && self.href == other.href
338
+ end
339
+
340
+ def to_json(*args)
341
+ "{\"src\":#{src.to_json}, \"href\":#{href.to_json}}"
342
+ end
343
+ end
344
+
345
+ def image(src,target)
346
+ ImageHolder.new(image_path(src),target.respond_to?(:to_str) ? target : url_for(target))
347
+ end
348
+
349
+ def action_link(text,target)
350
+ {:text=>text, :href=>target}
351
+ end
352
+
353
+ def requires_from_user?(from,body)
354
+ ! (announcement_notification?(from,body) or ref_update?(body) or profile_update?(body))
355
+ end
356
+
357
+ def profile_update?(body)
358
+ body.is_a?(Profile)
359
+ end
360
+
361
+ def ref_update?(body)
362
+ body.is_a?(Ref)
363
+ end
364
+
365
+ def announcement_notification?(from,body)
366
+ from.nil? and body.is_a?(Notification)
367
+ end
368
+
369
+ def send_message(method)
370
+ @recipients = @recipients.is_a?(Array) ? @recipients : [@recipients]
371
+ if from.nil? and @recipients.size==1 and requires_from_user?(from,_body)
372
+ @from = @recipients.first
373
+ end
374
+ # notifications can
375
+ # omit the from address
376
+ raise InvalidSender.new("Sender must be a Facebooker::User") unless from.is_a?(Facebooker::User) || !requires_from_user?(from,_body)
377
+ case _body
378
+ when Facebooker::Feed::TemplatizedAction,Facebooker::Feed::Action
379
+ from.publish_action(_body)
380
+ when Facebooker::Feed::Story
381
+ @recipients.each {|r| r.publish_story(_body)}
382
+ when Notification
383
+ (from.nil? ? Facebooker::Session.create : from.session).send_notification(@recipients,_body.fbml)
384
+ when Email
385
+ from.session.send_email(@recipients,
386
+ _body.title,
387
+ _body.text,
388
+ _body.fbml)
389
+ when Profile
390
+ # If recipient and from aren't the same person, create a new user object using the
391
+ # userid from recipient and the session from from
392
+ @from = Facebooker::User.new(Facebooker::User.cast_to_facebook_id(@recipients.first),Facebooker::Session.create)
393
+ @from.set_profile_fbml(_body.profile, _body.mobile_profile, _body.profile_action, _body.profile_main)
394
+ when Ref
395
+ Facebooker::Session.create.server_cache.set_ref_handle(_body.handle,_body.fbml)
396
+ when UserAction
397
+ @from.session.publish_user_action(_body.template_id,_body.data_hash,_body.target_ids,_body.body_general,_body.story_size)
398
+ else
399
+ raise UnspecifiedBodyType.new("You must specify a valid send_as")
400
+ end
401
+ end
402
+
403
+ # nodoc
404
+ # needed for actionview
405
+ def logger
406
+ RAILS_DEFAULT_LOGGER
407
+ end
408
+
409
+ # nodoc
410
+ # delegate to action view. Set up assigns and render
411
+ def render(opts)
412
+ opts = opts.dup
413
+ body = opts.delete(:assigns) || {}
414
+ initialize_template_class(body.dup.merge(:controller=>self)).render(opts)
415
+ end
416
+
417
+
418
+ def initialize_template_class(assigns)
419
+ template_root = "#{RAILS_ROOT}/app/views"
420
+ controller_root = File.join(template_root,self.class.controller_path)
421
+ #only do this on Rails 2.1
422
+ if ActionController::Base.respond_to?(:append_view_path)
423
+ # only add the view path once
424
+ unless ActionController::Base.view_paths.include?(controller_root)
425
+ ActionController::Base.append_view_path(controller_root)
426
+ ActionController::Base.append_view_path(controller_root+"/..")
427
+ end
428
+ view_paths = ActionController::Base.view_paths
429
+ else
430
+ view_paths = [template_root, controller_root]
431
+ end
432
+ returning ActionView::Base.new(view_paths, assigns, self) do |template|
433
+ template.controller=self
434
+ template.extend(self.class.master_helper_module)
435
+ def template.request_comes_from_facebook?
436
+ true
437
+ end
438
+ end
439
+ end
440
+
441
+
442
+ self.master_helper_module = Module.new
443
+ self.master_helper_module.module_eval do
444
+ # url_helper delegates to @controller,
445
+ # so we need to define that in the template
446
+ # we make it point to the publisher
447
+ include ActionView::Helpers::UrlHelper
448
+ include ActionView::Helpers::TextHelper
449
+ include ActionView::Helpers::TagHelper
450
+ include ActionView::Helpers::FormHelper
451
+ include ActionView::Helpers::FormTagHelper
452
+ include ActionView::Helpers::AssetTagHelper
453
+ include ActionView::Helpers::NumberHelper
454
+ include Facebooker::Rails::Helpers
455
+
456
+ #define this for the publisher views
457
+ def protect_against_forgery?
458
+ @paf ||= ActionController::Base.new.send(:protect_against_forgery?)
459
+ end
460
+
461
+ # url_for calls in publishers tend to want full paths
462
+ def url_for(options = {})
463
+ super(options.kind_of?(Hash) ? {:only_path => false}.update(options) : options)
464
+ end
465
+ end
466
+ ActionController::Routing::Routes.named_routes.install(self.master_helper_module)
467
+ include self.master_helper_module
468
+ class << self
469
+
470
+ def register_all_templates
471
+ all_templates = instance_methods.grep(/_template$/) - %w(short_story_template full_story_template one_line_story_template)
472
+ all_templates.each do |template|
473
+ template_name=template.sub(/_template$/,"")
474
+ puts "Registering #{template_name}"
475
+ send("register_"+template_name)
476
+ end
477
+ end
478
+
479
+ def method_missing(name,*args)
480
+ should_send = false
481
+ method = ''
482
+ if md = /^create_(.*)$/.match(name.to_s)
483
+ method = md[1]
484
+ elsif md = /^deliver_(.*)$/.match(name.to_s)
485
+ method = md[1]
486
+ should_send = true
487
+ elsif md = /^register_(.*)$/.match(name.to_s)
488
+ return FacebookTemplate.register(self, md[1])
489
+ else
490
+ super
491
+ end
492
+
493
+ #now create the item
494
+ (publisher=new).send(method,*args)
495
+ case publisher._body
496
+ when UserAction
497
+ publisher._body.template_name = method
498
+ publisher._body.template_id ||= FacebookTemplate.bundle_id_for_class_and_method(self,method)
499
+ end
500
+
501
+ should_send ? publisher.send_message(method) : publisher._body
502
+ end
503
+
504
+ def controller_path
505
+ self.to_s.underscore
506
+ end
507
+
508
+ def helper(*args)
509
+ args.each do |arg|
510
+ case arg
511
+ when Symbol,String
512
+ add_template_helper("#{arg.to_s.classify}Helper".constantize)
513
+ when Module
514
+ add_template_helper(arg)
515
+ end
516
+ end
517
+ end
518
+
519
+ def add_template_helper(helper_module) #:nodoc:
520
+ master_helper_module.send :include,helper_module
521
+ include master_helper_module
522
+ end
523
+
524
+
525
+ def inherited(child)
526
+ super
527
+ child.master_helper_module=Module.new
528
+ child.master_helper_module.__send__(:include,self.master_helper_module)
529
+ child.send(:include, child.master_helper_module)
530
+ FacebookTemplate.clear_cache!
531
+ end
532
+
533
+ end
534
+ class PublisherController
535
+ include Facebooker::Rails::Publisher.master_helper_module
536
+ include ActionController::UrlWriter
537
+
538
+ def initialize(source)
539
+ self.class.url_option_source = source
540
+ end
541
+
542
+ class << self
543
+ attr_accessor :url_option_source
544
+ alias :old_default_url_options :default_url_options
545
+ def default_url_options(*args)
546
+ url_option_source.default_url_options(*args)
547
+ end
548
+ end
549
+
550
+ end
551
+
552
+ end
553
+ end
554
+ 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