facebook_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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