yury-facebooker 0.9.5

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 (48) hide show
  1. data/CHANGELOG.txt +0 -0
  2. data/COPYING +19 -0
  3. data/History.txt +16 -0
  4. data/Manifest.txt +77 -0
  5. data/README +46 -0
  6. data/README.txt +81 -0
  7. data/Rakefile +62 -0
  8. data/TODO.txt +10 -0
  9. data/facebooker.yml.tpl +41 -0
  10. data/init.rb +53 -0
  11. data/install.rb +7 -0
  12. data/lib/facebooker.rb +143 -0
  13. data/lib/facebooker/data.rb +40 -0
  14. data/lib/facebooker/feed.rb +78 -0
  15. data/lib/facebooker/model.rb +123 -0
  16. data/lib/facebooker/parser.rb +518 -0
  17. data/lib/facebooker/rails/controller.rb +241 -0
  18. data/lib/facebooker/rails/facebook_asset_path.rb +18 -0
  19. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  20. data/lib/facebooker/rails/facebook_request_fix.rb +24 -0
  21. data/lib/facebooker/rails/facebook_session_handling.rb +58 -0
  22. data/lib/facebooker/rails/facebook_url_rewriting.rb +39 -0
  23. data/lib/facebooker/rails/helpers.rb +615 -0
  24. data/lib/facebooker/rails/routing.rb +49 -0
  25. data/lib/facebooker/rails/test_helpers.rb +88 -0
  26. data/lib/facebooker/rails/utilities.rb +22 -0
  27. data/lib/facebooker/server_cache.rb +24 -0
  28. data/lib/facebooker/service.rb +31 -0
  29. data/lib/facebooker/session.rb +550 -0
  30. data/lib/facebooker/version.rb +9 -0
  31. data/lib/net/http_multipart_post.rb +123 -0
  32. data/lib/tasks/facebooker.rake +17 -0
  33. data/lib/tasks/tunnel.rake +43 -0
  34. data/setup.rb +1585 -0
  35. data/test/event_test.rb +15 -0
  36. data/test/facebook_cache_test.rb +43 -0
  37. data/test/facebook_data_test.rb +50 -0
  38. data/test/facebooker_test.rb +855 -0
  39. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  40. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  41. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  42. data/test/http_multipart_post_test.rb +54 -0
  43. data/test/model_test.rb +91 -0
  44. data/test/rails_integration_test.rb +993 -0
  45. data/test/session_test.rb +559 -0
  46. data/test/test_helper.rb +60 -0
  47. data/test/user_test.rb +219 -0
  48. metadata +130 -0
@@ -0,0 +1,241 @@
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
+ end
13
+
14
+
15
+ def facebook_session
16
+ @facebook_session
17
+ end
18
+
19
+ def facebook_session_parameters
20
+ {:fb_sig_session_key=>params[:fb_sig_session_key]}
21
+ end
22
+
23
+
24
+ def set_facebook_session
25
+
26
+ returning session_set = session_already_secured? || secure_with_facebook_params! ||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
+ private
39
+
40
+ def session_already_secured?
41
+ (@facebook_session = session[:facebook_session]) && session[:facebook_session].secured? if valid_session_key_in_session?
42
+ end
43
+
44
+ def user_has_deauthorized_application?
45
+ # if we're inside the facebook session and there is no session key,
46
+ # that means the user revoked our access
47
+ # we don't want to keep using the old expired key from the cookie.
48
+ request_is_for_a_facebook_canvas? and params[:fb_sig_session_key].blank?
49
+ end
50
+
51
+ def clear_facebook_session_information
52
+ session[:facebook_session] = nil
53
+ @facebook_session=nil
54
+ end
55
+
56
+ def valid_session_key_in_session?
57
+ #before we access the facebook_params, make sure we have the parameters
58
+ #otherwise we will blow up trying to access the secure parameters
59
+ if user_has_deauthorized_application?
60
+ clear_facebook_session_information
61
+ false
62
+ else
63
+ !session[:facebook_session].blank? && (params[:fb_sig_session_key].blank? || session[:facebook_session].session_key == facebook_params[:session_key])
64
+ end
65
+ end
66
+
67
+ def secure_with_token!
68
+ if params['auth_token']
69
+ @facebook_session = new_facebook_session
70
+ @facebook_session.auth_token = params['auth_token']
71
+ @facebook_session.secure!
72
+ session[:facebook_session] = @facebook_session
73
+ end
74
+ end
75
+
76
+ def secure_with_facebook_params!
77
+ return unless request_is_for_a_facebook_canvas?
78
+
79
+ if ['user', 'session_key'].all? {|element| facebook_params[element]}
80
+ @facebook_session = new_facebook_session
81
+ @facebook_session.secure_with!(facebook_params['session_key'], facebook_params['user'], facebook_params['expires'])
82
+ session[:facebook_session] = @facebook_session
83
+ end
84
+ end
85
+
86
+ #override to specify where the user should be sent after logging in
87
+ def after_facebook_login_url
88
+ nil
89
+ end
90
+
91
+ def create_new_facebook_session_and_redirect!
92
+ session[:facebook_session] = new_facebook_session
93
+ url_params = after_facebook_login_url.nil? ? {} : {:next=>after_facebook_login_url}
94
+ redirect_to session[:facebook_session].login_url(url_params) unless @installation_required
95
+ false
96
+ end
97
+
98
+ def new_facebook_session
99
+ Facebooker::Session.create(Facebooker.api_key, Facebooker.secret_key)
100
+ end
101
+
102
+ def capture_facebook_friends_if_available!
103
+ return unless request_is_for_a_facebook_canvas?
104
+ if friends = facebook_params['friends']
105
+ facebook_session.user.friends = friends.map do |friend_uid|
106
+ User.new(friend_uid, facebook_session)
107
+ end
108
+ end
109
+ end
110
+
111
+ def blank?(value)
112
+ (value == '0' || value.nil? || value == '')
113
+ end
114
+
115
+ def verified_facebook_params
116
+ facebook_sig_params = params.inject({}) do |collection, pair|
117
+ collection[pair.first.sub(/^fb_sig_/, '')] = pair.last if pair.first[0,7] == 'fb_sig_'
118
+ collection
119
+ end
120
+ verify_signature(facebook_sig_params,params['fb_sig'])
121
+
122
+ facebook_sig_params.inject(HashWithIndifferentAccess.new) do |collection, pair|
123
+ collection[pair.first] = facebook_parameter_conversions[pair.first].call(pair.last)
124
+ collection
125
+ end
126
+ end
127
+
128
+ def earliest_valid_session
129
+ 48.hours.ago
130
+ end
131
+
132
+ def verify_signature(facebook_sig_params,expected_signature)
133
+ raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
134
+ actual_sig = Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
135
+ raise Facebooker::Session::IncorrectSignature if actual_sig != expected_signature
136
+ raise Facebooker::Session::SignatureTooOld if Time.at(facebook_sig_params['time'].to_f) < earliest_valid_session
137
+ true
138
+ end
139
+
140
+ def facebook_parameter_conversions
141
+ @facebook_parameter_conversions ||= Hash.new do |hash, key|
142
+ lambda{|value| value}
143
+ end.merge(
144
+ 'time' => lambda{|value| Time.at(value.to_f)},
145
+ 'in_canvas' => lambda{|value| !blank?(value)},
146
+ 'added' => lambda{|value| !blank?(value)},
147
+ 'expires' => lambda{|value| blank?(value) ? nil : Time.at(value.to_f)},
148
+ 'friends' => lambda{|value| value.split(/,/)}
149
+ )
150
+ end
151
+
152
+ def redirect_to(*args)
153
+ if request_is_for_a_facebook_canvas? and !request_is_facebook_tab?
154
+ render :text => fbml_redirect_tag(*args)
155
+ else
156
+ super
157
+ end
158
+ end
159
+
160
+ def fbml_redirect_tag(url)
161
+ "<fb:redirect url=\"#{url_for(url)}\" />"
162
+ end
163
+
164
+ def request_is_for_a_facebook_canvas?
165
+ !params['fb_sig_in_canvas'].blank?
166
+ end
167
+
168
+ def request_is_facebook_tab?
169
+ !params["fb_sig_in_profile_tab"].blank?
170
+ end
171
+
172
+ def request_is_facebook_ajax?
173
+ params["fb_sig_is_mockajax"]=="1" || params["fb_sig_is_ajax"]=="1"
174
+ end
175
+ def xml_http_request?
176
+ request_is_facebook_ajax? || super
177
+ end
178
+
179
+
180
+
181
+ def application_is_installed?
182
+ facebook_params['added']
183
+ end
184
+
185
+ def ensure_has_status_update
186
+ has_extended_permission?("status_update") || application_needs_permission("status_update")
187
+ end
188
+ def ensure_has_photo_upload
189
+ has_extended_permission?("photo_upload") || application_needs_permission("photo_upload")
190
+ end
191
+ def ensure_has_create_listing
192
+ has_extended_permission?("create_listing") || application_needs_permission("create_listing")
193
+ end
194
+
195
+ def application_needs_permission(perm)
196
+ redirect_to(facebook_session.permission_url(perm))
197
+ end
198
+
199
+ def has_extended_permission?(perm)
200
+ params["fb_sig_ext_perms"] and params["fb_sig_ext_perms"].include?(perm)
201
+ end
202
+
203
+ def ensure_authenticated_to_facebook
204
+ set_facebook_session || create_new_facebook_session_and_redirect!
205
+ end
206
+
207
+ def ensure_application_is_installed_by_facebook_user
208
+ @installation_required = true
209
+ returning ensure_authenticated_to_facebook && application_is_installed? do |authenticated_and_installed|
210
+ application_is_not_installed_by_facebook_user unless authenticated_and_installed
211
+ end
212
+ end
213
+
214
+ def application_is_not_installed_by_facebook_user
215
+ redirect_to session[:facebook_session].install_url
216
+ end
217
+
218
+ def set_fbml_format
219
+ params[:format]="fbml" if request_is_for_a_facebook_canvas? or request_is_facebook_ajax?
220
+ end
221
+ def set_adapter
222
+ Facebooker.load_adapter(params) if(params[:fb_sig_api_key])
223
+ end
224
+
225
+
226
+ module ClassMethods
227
+ #
228
+ # Creates a filter which reqires a user to have already authenticated to
229
+ # Facebook before executing actions. Accepts the same optional options hash which
230
+ # before_filter and after_filter accept.
231
+ def ensure_authenticated_to_facebook(options = {})
232
+ before_filter :ensure_authenticated_to_facebook, options
233
+ end
234
+
235
+ def ensure_application_is_installed_by_facebook_user(options = {})
236
+ before_filter :ensure_application_is_installed_by_facebook_user, options
237
+ end
238
+ end
239
+ end
240
+ end
241
+ 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,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
@@ -0,0 +1,58 @@
1
+ module ActionController
2
+ class CgiRequest
3
+ alias :initialize_aliased_by_facebooker :initialize
4
+
5
+ def initialize(cgi, session_options = {})
6
+ initialize_aliased_by_facebooker(cgi, session_options)
7
+ @cgi.instance_variable_set("@request_params", request_parameters.merge(query_parameters))
8
+ end
9
+
10
+ DEFAULT_SESSION_OPTIONS[:cookie_only] = false
11
+ end
12
+ end
13
+
14
+ class CGI
15
+ class Session
16
+ private
17
+ alias :initialize_aliased_by_facebooker :initialize
18
+ attr_reader :request, :initialization_options
19
+
20
+ def initialize(request, option={})
21
+ @request = request
22
+ @initialization_options = option
23
+ option['session_id'] = set_session_id
24
+ initialize_aliased_by_facebooker(request, option)
25
+ end
26
+
27
+ def set_session_id
28
+ if session_key_should_be_set_with_facebook_session_key?
29
+ request_parameters[facebook_session_key]
30
+ else
31
+ request_parameters[session_key]
32
+ end
33
+ end
34
+
35
+ def request_parameters
36
+ request.instance_variable_get("@request_params")
37
+ end
38
+
39
+ def session_key_should_be_set_with_facebook_session_key?
40
+ request_parameters[session_key].blank? && !request_parameters[facebook_session_key].blank?
41
+ end
42
+
43
+ def session_key
44
+ initialization_options['session_key'] || '_session_id'
45
+ end
46
+
47
+ def facebook_session_key
48
+ 'fb_sig_session_key'
49
+ end
50
+
51
+ alias :create_new_id_aliased_by_facebooker :create_new_id
52
+
53
+ def create_new_id
54
+ @new_session = true
55
+ @session_id || create_new_id_aliased_by_facebooker
56
+ end
57
+ end
58
+ end