cwninja-facebooker 1.0.8

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 (115) hide show
  1. data/CHANGELOG.txt +0 -0
  2. data/COPYING +19 -0
  3. data/History.txt +16 -0
  4. data/Manifest.txt +114 -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 +46 -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/generators/xd_receiver/templates/xd_receiver.html +10 -0
  41. data/generators/xd_receiver/xd_receiver_generator.rb +9 -0
  42. data/init.rb +70 -0
  43. data/install.rb +12 -0
  44. data/lib/facebooker.rb +160 -0
  45. data/lib/facebooker/adapters/adapter_base.rb +87 -0
  46. data/lib/facebooker/adapters/bebo_adapter.rb +75 -0
  47. data/lib/facebooker/adapters/facebook_adapter.rb +48 -0
  48. data/lib/facebooker/admin.rb +28 -0
  49. data/lib/facebooker/batch_request.rb +44 -0
  50. data/lib/facebooker/data.rb +57 -0
  51. data/lib/facebooker/feed.rb +78 -0
  52. data/lib/facebooker/logging.rb +51 -0
  53. data/lib/facebooker/model.rb +123 -0
  54. data/lib/facebooker/models/affiliation.rb +10 -0
  55. data/lib/facebooker/models/album.rb +11 -0
  56. data/lib/facebooker/models/applicationproperties.rb +39 -0
  57. data/lib/facebooker/models/cookie.rb +10 -0
  58. data/lib/facebooker/models/education_info.rb +11 -0
  59. data/lib/facebooker/models/event.rb +26 -0
  60. data/lib/facebooker/models/friend_list.rb +14 -0
  61. data/lib/facebooker/models/group.rb +35 -0
  62. data/lib/facebooker/models/info_item.rb +10 -0
  63. data/lib/facebooker/models/info_section.rb +10 -0
  64. data/lib/facebooker/models/location.rb +8 -0
  65. data/lib/facebooker/models/notifications.rb +17 -0
  66. data/lib/facebooker/models/page.rb +27 -0
  67. data/lib/facebooker/models/photo.rb +10 -0
  68. data/lib/facebooker/models/tag.rb +12 -0
  69. data/lib/facebooker/models/user.rb +369 -0
  70. data/lib/facebooker/models/work_info.rb +9 -0
  71. data/lib/facebooker/parser.rb +547 -0
  72. data/lib/facebooker/rails/controller.rb +280 -0
  73. data/lib/facebooker/rails/facebook_asset_path.rb +18 -0
  74. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  75. data/lib/facebooker/rails/facebook_pretty_errors.rb +14 -0
  76. data/lib/facebooker/rails/facebook_request_fix.rb +24 -0
  77. data/lib/facebooker/rails/facebook_session_handling.rb +69 -0
  78. data/lib/facebooker/rails/facebook_url_helper.rb +191 -0
  79. data/lib/facebooker/rails/facebook_url_rewriting.rb +39 -0
  80. data/lib/facebooker/rails/helpers.rb +642 -0
  81. data/lib/facebooker/rails/helpers/fb_connect.rb +34 -0
  82. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  83. data/lib/facebooker/rails/publisher.rb +511 -0
  84. data/lib/facebooker/rails/routing.rb +49 -0
  85. data/lib/facebooker/rails/test_helpers.rb +88 -0
  86. data/lib/facebooker/rails/utilities.rb +22 -0
  87. data/lib/facebooker/server_cache.rb +24 -0
  88. data/lib/facebooker/service.rb +83 -0
  89. data/lib/facebooker/session.rb +564 -0
  90. data/lib/facebooker/version.rb +9 -0
  91. data/lib/net/http_multipart_post.rb +123 -0
  92. data/lib/tasks/facebooker.rake +18 -0
  93. data/lib/tasks/tunnel.rake +46 -0
  94. data/rails/init.rb +1 -0
  95. data/setup.rb +1585 -0
  96. data/templates/layout.erb +24 -0
  97. data/test/adapters_test.rb +98 -0
  98. data/test/batch_request_test.rb +82 -0
  99. data/test/event_test.rb +15 -0
  100. data/test/facebook_admin_test.rb +76 -0
  101. data/test/facebook_cache_test.rb +44 -0
  102. data/test/facebook_data_test.rb +86 -0
  103. data/test/facebooker_test.rb +855 -0
  104. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  105. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  106. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  107. data/test/http_multipart_post_test.rb +54 -0
  108. data/test/logging_test.rb +43 -0
  109. data/test/model_test.rb +91 -0
  110. data/test/publisher_test.rb +458 -0
  111. data/test/rails_integration_test.rb +1221 -0
  112. data/test/session_test.rb +613 -0
  113. data/test/test_helper.rb +60 -0
  114. data/test/user_test.rb +270 -0
  115. metadata +185 -0
@@ -0,0 +1,280 @@
1
+ require 'facebooker'
2
+ require 'facebooker/rails/profile_publisher_extensions'
3
+ module Facebooker
4
+ module Rails
5
+ module Controller
6
+ include Facebooker::Rails::ProfilePublisherExtensions
7
+ def self.included(controller)
8
+ controller.extend(ClassMethods)
9
+ controller.before_filter :set_adapter
10
+ controller.before_filter :set_fbml_format
11
+ controller.helper_attr :facebook_session_parameters
12
+ controller.helper_method :request_comes_from_facebook?
13
+ end
14
+
15
+
16
+ def facebook_session
17
+ @facebook_session
18
+ end
19
+
20
+ def facebook_session_parameters
21
+ {:fb_sig_session_key=>params[:fb_sig_session_key]}
22
+ end
23
+
24
+
25
+ def set_facebook_session
26
+ returning session_set = session_already_secured? || secure_with_facebook_params! || secure_with_cookies! || secure_with_token! do
27
+ if session_set
28
+ capture_facebook_friends_if_available!
29
+ Session.current = facebook_session
30
+ end
31
+ end
32
+ end
33
+
34
+ def facebook_params
35
+ @facebook_params ||= verified_facebook_params
36
+ end
37
+
38
+ def redirect_to(*args)
39
+ if request_is_for_a_facebook_canvas? and !request_is_facebook_tab?
40
+ render :text => fbml_redirect_tag(*args)
41
+ else
42
+ super
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def session_already_secured?
49
+ (@facebook_session = session[:facebook_session]) && session[:facebook_session].secured? if valid_session_key_in_session?
50
+ end
51
+
52
+ def user_has_deauthorized_application?
53
+ # if we're inside the facebook session and there is no session key,
54
+ # that means the user revoked our access
55
+ # we don't want to keep using the old expired key from the cookie.
56
+ request_comes_from_facebook? and params[:fb_sig_session_key].blank?
57
+ end
58
+
59
+ def clear_facebook_session_information
60
+ session[:facebook_session] = nil
61
+ @facebook_session=nil
62
+ end
63
+
64
+ def valid_session_key_in_session?
65
+ #before we access the facebook_params, make sure we have the parameters
66
+ #otherwise we will blow up trying to access the secure parameters
67
+ if user_has_deauthorized_application?
68
+ clear_facebook_session_information
69
+ false
70
+ else
71
+ !session[:facebook_session].blank? && (params[:fb_sig_session_key].blank? || session[:facebook_session].session_key == facebook_params[:session_key])
72
+ end
73
+ end
74
+
75
+ def clear_fb_cookies!
76
+ domain_cookie_tag = "base_domain_#{Facebooker.api_key}"
77
+ cookie_domain = ".#{cookies[domain_cookie_tag]}" if cookies[domain_cookie_tag]
78
+ fb_cookie_names.each {|name| cookies.delete(name, :domain=>cookie_domain)}
79
+ cookies.delete Facebooker.api_key
80
+ end
81
+
82
+ def fb_cookie_prefix
83
+ Facebooker.api_key+"_"
84
+ end
85
+
86
+ def fb_cookie_names
87
+ fb_cookie_names = cookies.keys.select{|k| k.starts_with?(fb_cookie_prefix)}
88
+ end
89
+
90
+ def secure_with_cookies!
91
+ parsed = {}
92
+
93
+ fb_cookie_names.each { |key| parsed[key[fb_cookie_prefix.size,key.size]] = cookies[key] }
94
+
95
+ #returning gracefully if the cookies aren't set or have expired
96
+ return unless parsed['session_key'] && parsed['user'] && parsed['expires'] && parsed['ss']
97
+ return unless Time.at(parsed['expires'].to_f) > Time.now
98
+
99
+ #if we have the unexpired cookies, we'll throw an exception if the sig doesn't verify
100
+ verify_signature(parsed,cookies[Facebooker.api_key])
101
+
102
+ @facebook_session = new_facebook_session
103
+ @facebook_session.secure_with!(parsed['session_key'],parsed['user'],parsed['expires'],parsed['ss'])
104
+ end
105
+
106
+ def secure_with_token!
107
+ if params['auth_token']
108
+ @facebook_session = new_facebook_session
109
+ @facebook_session.auth_token = params['auth_token']
110
+ @facebook_session.secure!
111
+ session[:facebook_session] = @facebook_session
112
+ end
113
+ end
114
+
115
+ def secure_with_facebook_params!
116
+ return unless request_comes_from_facebook?
117
+
118
+ if ['user', 'session_key'].all? {|element| facebook_params[element]}
119
+ @facebook_session = new_facebook_session
120
+ @facebook_session.secure_with!(facebook_params['session_key'], facebook_params['user'], facebook_params['expires'])
121
+ session[:facebook_session] = @facebook_session
122
+ end
123
+ end
124
+
125
+ #override to specify where the user should be sent after logging in
126
+ def after_facebook_login_url
127
+ nil
128
+ end
129
+
130
+ def create_new_facebook_session_and_redirect!
131
+ session[:facebook_session] = new_facebook_session
132
+ url_params = after_facebook_login_url.nil? ? {} : {:next=>after_facebook_login_url}
133
+ redirect_to session[:facebook_session].login_url(url_params) unless @installation_required
134
+ false
135
+ end
136
+
137
+ def new_facebook_session
138
+ Facebooker::Session.create(Facebooker.api_key, Facebooker.secret_key)
139
+ end
140
+
141
+ def capture_facebook_friends_if_available!
142
+ return unless request_comes_from_facebook?
143
+ if friends = facebook_params['friends']
144
+ facebook_session.user.friends = friends.map do |friend_uid|
145
+ User.new(friend_uid, facebook_session)
146
+ end
147
+ end
148
+ end
149
+
150
+ def blank?(value)
151
+ (value == '0' || value.nil? || value == '')
152
+ end
153
+
154
+ def verified_facebook_params
155
+ facebook_sig_params = params.inject({}) do |collection, pair|
156
+ collection[pair.first.sub(/^fb_sig_/, '')] = pair.last if pair.first[0,7] == 'fb_sig_'
157
+ collection
158
+ end
159
+ verify_signature(facebook_sig_params,params['fb_sig'])
160
+
161
+ facebook_sig_params.inject(HashWithIndifferentAccess.new) do |collection, pair|
162
+ collection[pair.first] = facebook_parameter_conversions[pair.first].call(pair.last)
163
+ collection
164
+ end
165
+ end
166
+
167
+ def earliest_valid_session
168
+ 48.hours.ago
169
+ end
170
+
171
+ def verify_signature(facebook_sig_params,expected_signature)
172
+ raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
173
+ actual_sig = Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
174
+ raise Facebooker::Session::IncorrectSignature if actual_sig != expected_signature
175
+ raise Facebooker::Session::SignatureTooOld if facebook_sig_params['time'] && Time.at(facebook_sig_params['time'].to_f) < earliest_valid_session
176
+ true
177
+ end
178
+
179
+ def facebook_parameter_conversions
180
+ @facebook_parameter_conversions ||= Hash.new do |hash, key|
181
+ lambda{|value| value}
182
+ end.merge(
183
+ 'time' => lambda{|value| Time.at(value.to_f)},
184
+ 'in_canvas' => lambda{|value| !blank?(value)},
185
+ 'added' => lambda{|value| !blank?(value)},
186
+ 'expires' => lambda{|value| blank?(value) ? nil : Time.at(value.to_f)},
187
+ 'friends' => lambda{|value| value.split(/,/)}
188
+ )
189
+ end
190
+
191
+ def fbml_redirect_tag(url)
192
+ "<fb:redirect url=\"#{url_for(url)}\" />"
193
+ end
194
+
195
+ def request_comes_from_facebook?
196
+ request_is_for_a_facebook_canvas? || request_is_facebook_ajax? || request_is_fb_ping?
197
+ end
198
+
199
+ def request_is_fb_ping?
200
+ !params['fb_sig'].blank?
201
+ end
202
+
203
+ def request_is_for_a_facebook_canvas?
204
+ !params['fb_sig_in_canvas'].blank?
205
+ end
206
+
207
+ def request_is_facebook_tab?
208
+ !params["fb_sig_in_profile_tab"].blank?
209
+ end
210
+
211
+ def request_is_facebook_ajax?
212
+ params["fb_sig_is_mockajax"]=="1" || params["fb_sig_is_ajax"]=="1"
213
+ end
214
+ def xml_http_request?
215
+ request_is_facebook_ajax? || super
216
+ end
217
+
218
+
219
+
220
+ def application_is_installed?
221
+ facebook_params['added']
222
+ end
223
+
224
+ def ensure_has_status_update
225
+ has_extended_permission?("status_update") || application_needs_permission("status_update")
226
+ end
227
+ def ensure_has_photo_upload
228
+ has_extended_permission?("photo_upload") || application_needs_permission("photo_upload")
229
+ end
230
+ def ensure_has_create_listing
231
+ has_extended_permission?("create_listing") || application_needs_permission("create_listing")
232
+ end
233
+
234
+ def application_needs_permission(perm)
235
+ redirect_to(facebook_session.permission_url(perm))
236
+ end
237
+
238
+ def has_extended_permission?(perm)
239
+ params["fb_sig_ext_perms"] and params["fb_sig_ext_perms"].include?(perm)
240
+ end
241
+
242
+ def ensure_authenticated_to_facebook
243
+ set_facebook_session || create_new_facebook_session_and_redirect!
244
+ end
245
+
246
+ def ensure_application_is_installed_by_facebook_user
247
+ @installation_required = true
248
+ returning ensure_authenticated_to_facebook && application_is_installed? do |authenticated_and_installed|
249
+ application_is_not_installed_by_facebook_user unless authenticated_and_installed
250
+ end
251
+ end
252
+
253
+ def application_is_not_installed_by_facebook_user
254
+ redirect_to session[:facebook_session].install_url
255
+ end
256
+
257
+ def set_fbml_format
258
+ params[:format]="fbml" if request_comes_from_facebook?
259
+ end
260
+ def set_adapter
261
+ Facebooker.load_adapter(params) if(params[:fb_sig_api_key])
262
+ end
263
+
264
+
265
+ module ClassMethods
266
+ #
267
+ # Creates a filter which reqires a user to have already authenticated to
268
+ # Facebook before executing actions. Accepts the same optional options hash which
269
+ # before_filter and after_filter accept.
270
+ def ensure_authenticated_to_facebook(options = {})
271
+ before_filter :ensure_authenticated_to_facebook, options
272
+ end
273
+
274
+ def ensure_application_is_installed_by_facebook_user(options = {})
275
+ before_filter :ensure_application_is_installed_by_facebook_user, options
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,18 @@
1
+ # module ActionView
2
+ # module Helpers
3
+ # module AssetTagHelper
4
+ # def compute_public_path_with_facebooker(*args)
5
+ # public_path=compute_public_path_without_facebooker(*args)
6
+ # if public_path.starts_with?(ActionController::Base.asset_host)
7
+ # str=ActionController::Base.asset_host
8
+ # str += "/" unless str.ends_with?("/")
9
+ # public_path.gsub(/#{Regexp.escape(ActionController::Base.asset_host)}#{@controller.request.relative_url_root}\//,str)
10
+ # else
11
+ # public_path
12
+ # end
13
+ # end
14
+ #
15
+ # alias_method_chain :compute_public_path, :facebooker
16
+ # end
17
+ # end
18
+ # end
@@ -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,14 @@
1
+ if Facebooker.facebooker_config['pretty_errors'] || (Facebooker.facebooker_config['pretty_errors'].nil? && RAILS_ENV=="development")
2
+ class ActionController::Base
3
+ def rescues_path_with_facebooker(template_name)
4
+ t="#{RAILS_ROOT}/vendor/plugins/facebooker/templates/#{template_name}.erb"
5
+ File.exist?(t) ? t : rescues_path_without_facebooker(template_name)
6
+ end
7
+
8
+ alias_method_chain :rescues_path,:facebooker
9
+
10
+ def response_code_for_rescue(exception)
11
+ 200
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ module ::ActionController
2
+ class AbstractRequest
3
+ def request_method_with_facebooker
4
+ if parameters[:fb_sig_request_method]=="GET" and parameters[:_method].blank?
5
+ parameters[:_method]="GET"
6
+ end
7
+ request_method_without_facebooker
8
+ end
9
+
10
+ if new.methods.include?("request_method")
11
+ alias_method_chain :request_method, :facebooker
12
+ end
13
+
14
+ def xml_http_request_with_facebooker?
15
+ parameters["fb_sig_is_mockajax"] == "1" ||
16
+ parameters["fb_sig_is_ajax"] == "1" ||
17
+ xml_http_request_without_facebooker?
18
+ end
19
+ alias_method_chain :xml_http_request?, :facebooker
20
+ # we have to re-alias xhr? since it was pointing to the old method
21
+ alias xhr? :xml_http_request?
22
+
23
+ end
24
+ end