facebook_rails 0.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 (45) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +38 -0
  4. data/app/controllers/facebook_rails_controller.rb +191 -0
  5. data/app/helpers/facebook_rails_helper.rb +90 -0
  6. data/lib/facebook_rails/engine.rb +48 -0
  7. data/lib/facebook_rails/version.rb +3 -0
  8. data/lib/facebook_rails.rb +17 -0
  9. data/lib/generators/facebook_rails/facebook_rails_generator.rb +11 -0
  10. data/lib/generators/facebook_rails/templates/facebook.yml +29 -0
  11. data/lib/tasks/facebook_rails_tasks.rake +4 -0
  12. data/test/dummy/README.rdoc +261 -0
  13. data/test/dummy/Rakefile +7 -0
  14. data/test/dummy/app/assets/javascripts/application.js +15 -0
  15. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  16. data/test/dummy/app/controllers/application_controller.rb +3 -0
  17. data/test/dummy/app/helpers/application_helper.rb +2 -0
  18. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  19. data/test/dummy/config/application.rb +56 -0
  20. data/test/dummy/config/boot.rb +10 -0
  21. data/test/dummy/config/database.yml +25 -0
  22. data/test/dummy/config/environment.rb +5 -0
  23. data/test/dummy/config/environments/development.rb +37 -0
  24. data/test/dummy/config/environments/production.rb +67 -0
  25. data/test/dummy/config/environments/test.rb +37 -0
  26. data/test/dummy/config/facebook.yml +26 -0
  27. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  28. data/test/dummy/config/initializers/inflections.rb +15 -0
  29. data/test/dummy/config/initializers/mime_types.rb +5 -0
  30. data/test/dummy/config/initializers/secret_token.rb +7 -0
  31. data/test/dummy/config/initializers/session_store.rb +8 -0
  32. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  33. data/test/dummy/config/locales/en.yml +5 -0
  34. data/test/dummy/config/routes.rb +58 -0
  35. data/test/dummy/config.ru +4 -0
  36. data/test/dummy/db/test.sqlite3 +0 -0
  37. data/test/dummy/log/test.log +6 -0
  38. data/test/dummy/public/404.html +26 -0
  39. data/test/dummy/public/422.html +26 -0
  40. data/test/dummy/public/500.html +25 -0
  41. data/test/dummy/public/favicon.ico +0 -0
  42. data/test/dummy/script/rails +6 -0
  43. data/test/facebook_rails_test.rb +7 -0
  44. data/test/test_helper.rb +15 -0
  45. metadata +156 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = FacebookRails
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'FacebookRails'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,191 @@
1
+ require 'cgi'
2
+
3
+ module FacebookRailsController
4
+ def facebook_href(path = '/')
5
+ FACEBOOK['f8app_home'].to_s + path
6
+ end
7
+
8
+ def direct_href(path = '/')
9
+ FACEBOOK['f8app_callback'].to_s + path
10
+ end
11
+
12
+ def facebook_api
13
+ @facebook_api ||= Koala::Facebook::API.new(session[:access_token])
14
+ end
15
+
16
+ def current_user_data
17
+ @current_user_data ||= facebook_api.get_object("me")
18
+ return @current_user_data || {}
19
+ end
20
+
21
+ def current_user_f8id
22
+ session[:user_f8id] ||= current_user_data["id"]
23
+ end
24
+
25
+ def current_user_friends_f8ids
26
+ @current_user_friends_f8ids ||= facebook_api.get_connections('me','friends', :fields => 'id').collect { |f| f['id']}
27
+ rescue Exception => e
28
+ logger.error 'FACEBOOK ERROR: ' + e.to_s
29
+ return []
30
+ end
31
+
32
+ def check_if_f8ids_are_friends(first_f8id, second_f8id)
33
+ #handle corner cases with anonymous users
34
+ return false if first_f8id.nil? or second_f8id.nil?
35
+
36
+ return (facebook_api.fql_query('SELECT uid2 FROM friend where uid1=' + first_f8id + ' AND uid2=' + second_f8id).size > 0)
37
+ rescue Exception => e
38
+ logger.error "ERROR:" + e.to_s
39
+ return false
40
+ end
41
+
42
+ def url_smart_add_params(url, params = {})
43
+ new_url = url + (url.index(/\w\?\w/) ? '&' : '?')
44
+ params.each_pair {|key, value| new_url << key.to_s << "=" << value.to_s << '&'}
45
+ return new_url.chop
46
+ end
47
+
48
+ def clean_and_recode_current_url(escape = true)
49
+ omit_keys = ["_method", "format", "signed_request", "code", "clear_users_session"]
50
+ options = (params||{}).clone
51
+ options = options.reject{|k,v| omit_keys.include?(k.to_s)}
52
+ options = options.merge({:only_path => false})
53
+ if escape
54
+ return CGI.escape(url_for(options))
55
+ else
56
+ return url_for(options)
57
+ end
58
+ end
59
+
60
+ def top_redirect_to(url)
61
+ @redirect_url = CGI.unescape(url)
62
+ render :layout => false, :inline => <<-HTML
63
+ <html><head>
64
+ <script type="text/javascript">
65
+ window.top.location.href = "<%=raw @redirect_url -%>";
66
+ </script>
67
+ <noscript>
68
+ <meta http-equiv="refresh" content="0;url=<%= @redirect_url %>" />
69
+ <meta http-equiv="window-target" content="_top" />
70
+ </noscript>
71
+ </head></html>
72
+ HTML
73
+ end
74
+
75
+ def authenticated_by_facebook?
76
+ return !session[:access_token].nil?
77
+ end
78
+
79
+ #Will only try to collect facebook credentials but it will let the user in even there aren't any
80
+ def try_facebook_authentication
81
+ attempt_to_acquire_facebook_credentials do |fb_oauth|
82
+ clear_oauth
83
+ end
84
+ rescue Exception => e
85
+ clear_oauth
86
+ logger.error "FACEBOOK AUTH EXCEPTION: #{ e.inspect } #{ e.backtrace }"
87
+ end
88
+
89
+ #Will force user to authorize the application to access the current url
90
+ def ensure_authenticated_to_facebook
91
+ attempt_to_acquire_facebook_credentials do |fb_oauth|
92
+ if params[:error_reason] == "user_denied"
93
+ redirect_url = root_url
94
+ else
95
+ redirect_url = fb_oauth.url_for_oauth_code(:callback => clean_and_recode_current_url, :permissions => Game.extended_permissions)
96
+ end
97
+ top_redirect_to(redirect_url)
98
+ end
99
+ rescue Exception => e
100
+ logger.error 'AUTHENTICATION ERROR: ' + e.to_s
101
+ top_redirect_to clean_and_recode_current_url(false)
102
+ end
103
+
104
+ #prepend before filter to force authentication when collect_facebook_authentication is called
105
+ def require_facebook_authentication
106
+ @require_fb_authentication = true
107
+ end
108
+
109
+ #Add method to before filter to collect user
110
+ def collect_facebook_authentication
111
+ if @require_fb_authentication
112
+ ensure_authenticated_to_facebook
113
+ else
114
+ try_facebook_authentication
115
+ end
116
+ end
117
+
118
+ def get_facebook_locale
119
+ puts current_user_data.inspect
120
+ current_user_data["locale"]
121
+ rescue Exception => e
122
+ logger.warn "Facebook locale error: #{ e.inspect }"
123
+ session[:f8_locale] || "en_US"
124
+ end
125
+
126
+ private
127
+ #Tries to extract facebook credentials, if it thinks a redirect is needed it yields to the block
128
+ #and returns false else it returns true
129
+ #Will let exceptions propagate
130
+ def attempt_to_acquire_facebook_credentials
131
+ if params[:clear_users_session]
132
+ clear_oauth
133
+ logger.warn "User's session cleared"
134
+ end
135
+
136
+ #First check we received the call with a signed_request parameter, as that means a fresh token
137
+ if params[:signed_request]
138
+ fb_oauth = Koala::Facebook::OAuth.new
139
+ f8_params = fb_oauth.parse_signed_request(params.delete(:signed_request))
140
+ session[:f8_locale] = (f8_params and f8_params["user"]) ? f8_params["user"]["locale"] : nil
141
+ #puts "request params: #{ f8_params.inspect }"
142
+ if f8_params["oauth_token"]
143
+ set_oauth f8_params["oauth_token"], f8_params["expires"].to_i, f8_params["user_id"]
144
+ else
145
+ yield(fb_oauth)
146
+ return false
147
+ end
148
+
149
+ #Then check if received a code because we just came from authorization, that also means a fresh token
150
+ elsif params[:code]
151
+ fb_oauth = Koala::Facebook::OAuth.new(clean_and_recode_current_url(false))
152
+ oauth_token_info = fb_oauth.get_access_token_info(params.delete(:code))
153
+ #puts "code params: #{ oauth_token_info.inspect }"
154
+ set_oauth oauth_token_info['access_token'], Time.now.to_i + oauth_token_info['expires'].to_i, nil
155
+
156
+ else
157
+ #Try to parse cookies
158
+ fb_oauth = Koala::Facebook::OAuth.new
159
+ f8_params = fb_oauth.get_user_info_from_cookies(cookies)
160
+ #puts "cookie params: #{ f8_params.inspect }"
161
+ if f8_params and f8_params["access_token"]
162
+ set_oauth f8_params["access_token"], Time.now.to_i + f8_params["expires"].to_i, f8_params["user_id"]
163
+
164
+ #Then we check if have a valid token stored in the session
165
+ #puts "session: #{ session.inspect }"
166
+ elsif session[:access_token] and session[:expires] > Time.now.to_i
167
+ #Do nothing
168
+
169
+ #if all else fails (we lost the session or something went wrong in the request sending) redirect the authorization
170
+ #screen. If the user has already authorized the application he will pass straight through without noticing and we
171
+ #will receive a fresh token via the code parameter
172
+ else
173
+ yield(fb_oauth)
174
+ return false
175
+ end
176
+ end
177
+
178
+ return true
179
+ end
180
+
181
+ def set_oauth(access_token = nil, expires = nil, user_f8id = nil)
182
+ session[:access_token] = access_token
183
+ session[:expires] = expires
184
+ session[:user_f8id] = user_f8id
185
+ @facebook_api = nil
186
+ end
187
+
188
+ def clear_oauth
189
+ set_oauth nil, nil, nil
190
+ end
191
+ end
@@ -0,0 +1,90 @@
1
+ module FacebookRailsHelper
2
+ def reload_back_to_facebook_if_needed_js
3
+ return '<script>' +
4
+ 'if (top == self)' +
5
+ '{' +
6
+ "top.location = '#{facebook_href(url_for( { :controller => controller.controller_name, :action => controller.action_name}.merge params.reject {|k,v| k == 'signed_request'}))}';" +
7
+ '}' +
8
+ '</script>'
9
+ end
10
+
11
+ def facebook_initialization one_time_resize = false, app_id = FACEBOOK['app_id'], user_f8id = current_user_f8id
12
+ resize = %{
13
+ var domLoaded = false;
14
+ var facebookLoaded = false;
15
+ var pageLoaded = false;
16
+
17
+ function pageLoad() {
18
+ if (domLoaded && facebookLoaded) {
19
+ if (!pageLoaded) {
20
+ pageLoaded = true;
21
+ $(document).trigger('page_loaded');
22
+ }
23
+ sizeToMain();
24
+ }
25
+ }
26
+
27
+ function sizeToMain() {
28
+ if (domLoaded && facebookLoaded) {
29
+ var height = $('#main').outerHeight();
30
+ if(height > 100) {
31
+ FB.Canvas.setSize({ width: 760, height: height + 200 });
32
+ }
33
+ }
34
+ }
35
+
36
+ $(document).ready(function () {
37
+ domLoaded = true;
38
+ pageLoad();
39
+ });
40
+ $(window).load(function() {
41
+ domLoaded = true; //not neccessary
42
+ pageLoad();
43
+ });
44
+ }
45
+
46
+ login_status = if user_f8id
47
+ %{
48
+ FB.getLoginStatus(function(response) {
49
+ if ((response.authResponse && response.authResponse.userID == '#{ user_f8id }') ||
50
+ (response.session && response.session.uid == '#{ user_f8id }')) {
51
+ // logged in and connected user - continue
52
+ $(document).trigger('got_facebook_status');
53
+ } else {
54
+ // no user session available or new user - clear old user's session
55
+ window.location.href = window.location.href + (window.location.href.indexOf('?') >= 0 ? '&' : '?') + 'clear_users_session=true';
56
+ }
57
+ }, true); //force session status reloading
58
+ }
59
+ else
60
+ %{
61
+ FB.getLoginStatus(function(response) {
62
+ $(document).trigger('got_facebook_status');
63
+ });
64
+ }
65
+ end
66
+
67
+ %{
68
+ <div id="fb-root"></div>
69
+ <script>
70
+ #{ resize if one_time_resize }
71
+ window.fbAsyncInit = function() {
72
+ FB.init({ appId: '#{ app_id }',
73
+ status: true,
74
+ cookie: true,
75
+ xfbml: true });
76
+ $(document).trigger('facebook_init');
77
+ #{ one_time_resize ? 'facebookLoaded = true; pageLoad();' : 'FB.Canvas.setAutoGrow();' }
78
+ #{ login_status }
79
+ };
80
+
81
+ (function() {
82
+ var e = document.createElement('script'); e.async = true;
83
+ e.src = document.location.protocol +
84
+ '//connect.facebook.net/#{ get_facebook_locale }/all.js';
85
+ document.getElementById('fb-root').appendChild(e);
86
+ }());
87
+ </script>
88
+ }.html_safe
89
+ end
90
+ end
@@ -0,0 +1,48 @@
1
+ require 'koala'
2
+
3
+ module FacebookRails
4
+
5
+ class Engine < Rails::Engine
6
+
7
+ initializer "facebook_rails.load_app_instance_data" do |app|
8
+ FacebookRails.setup do |config|
9
+ config.app_root = app.root
10
+ config.app_env = Rails.env
11
+ end
12
+ end
13
+
14
+ initializer "facebook_rails.facebook" do
15
+ ::FACEBOOK = YAML.load_file(FacebookRails.app_root.join("config/facebook.yml"))[Rails.env]
16
+ FACEBOOK.default = ''
17
+
18
+ ::Koala.http_service.http_options[:timeout] = FACEBOOK[:timeout].to_i unless FACEBOOK[:timeout].blank?
19
+
20
+ ::Koala::Facebook::OAuth.class_eval do
21
+ def initialize_with_default_settings(*args)
22
+ case args.size
23
+ when 0, 1
24
+ raise "application id and/or secret are not specified in the config" unless FACEBOOK['app_id'] && FACEBOOK['secret_key']
25
+ initialize_without_default_settings(FACEBOOK['app_id'].to_s, FACEBOOK['secret_key'].to_s, args.first)
26
+ when 2, 3
27
+ initialize_without_default_settings(*args)
28
+ end
29
+ end
30
+
31
+ alias_method_chain :initialize, :default_settings
32
+ end
33
+ end
34
+
35
+ initializer "facebook_rails.application_controller" do
36
+ ActionController::Base.send :include, FacebookRailsController
37
+
38
+ ActionController::Base.send :helper_method, :facebook_href
39
+ ActionController::Base.send :helper_method, :direct_href
40
+ ActionController::Base.send :helper_method, :current_user_f8id
41
+ ActionController::Base.send :helper_method, :get_facebook_locale
42
+ end
43
+
44
+ initializer "facebook_rails.application_helper" do
45
+ ActionView::Base.send :include, FacebookRailsHelper
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module FacebookRails
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,17 @@
1
+ require "active_support/dependencies"
2
+
3
+ module FacebookRails
4
+
5
+ # Our host application root path
6
+ # We set this when the engine is initialized
7
+ mattr_accessor :app_root
8
+ mattr_accessor :app_env
9
+
10
+ # Yield self on setup for nice config blocks
11
+ def self.setup
12
+ yield self
13
+ end
14
+
15
+ end
16
+
17
+ require 'facebook_rails/engine'
@@ -0,0 +1,11 @@
1
+ require 'rails/generators'
2
+
3
+ class FacebookRailsGenerator < Rails::Generators::Base
4
+ def self.source_root
5
+ @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+ end
7
+
8
+ def copy_configuration
9
+ template 'facebook.yml', 'config/facebook.yml'
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ #TODO Go to https://developers.facebook.com/apps, create a new App and enter the correct values here
2
+
3
+ # config/facebook.yml
4
+ development:
5
+ app_id: YOUR_APP_ID
6
+ secret_key: YOUR_SECRET
7
+ #Slijede drap dodaci
8
+ f8app_home: http://apps.facebook.com/CANVAS_NAME #bez zadnjeg '/'
9
+ f8app_callback: CALLBACK_URL #bez zadnjeg '/'
10
+ #server_subdir:
11
+ timeout: 3
12
+
13
+ test:
14
+ app_id: YOUR_APP_ID
15
+ secret_key: YOUR_SECRET
16
+ #Slijede drap dodaci
17
+ f8app_home: CANVAS_URL #bez zadnjeg '/'
18
+ f8app_callback: CALLBACK_URL #bez zadnjeg '/'
19
+ #server_subdir:
20
+ timeout: 3
21
+
22
+ production:
23
+ app_id: YOUR_APP_ID
24
+ secret_key: YOUR_SECRET
25
+ #Slijede drap dodaci
26
+ f8app_home: CANVAS_URL #bez zadnjeg '/'
27
+ f8app_callback: CALLBACK_URL #bez zadnjeg '/'
28
+ #server_subdir:
29
+ timeout: 3
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :facebook_rails do
3
+ # # Task goes here
4
+ # end