ryw-facebooker2 0.0.5.x2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ # Provides rails helpers for interfacing with Facebook's OpenGraph Javascript
2
+ # API, http://developers.facebook.com/docs/reference/javascript/.
3
+
4
+ require "mogli"
5
+ require "facebooker2/rails/controller"
6
+ require "facebooker2/rails/helpers/facebook_connect"
7
+ require "facebooker2/rails/helpers/javascript"
8
+ require "facebooker2/rails/helpers/request_forms"
9
+ require "facebooker2/rails/helpers/user"
10
+ require "facebooker2/rails/helpers"
11
+ require "facebooker2/not_configured"
12
+
13
+ module Facebooker2
14
+
15
+ # provide cached access to configuration
16
+ class << self
17
+ attr_accessor :api_key, :secret, :app_id
18
+ end
19
+
20
+ # provide cached access to the configured application secret
21
+ def self.secret
22
+ @secret || raise_unconfigured_exception
23
+ end
24
+
25
+ # provide cached access to the configured app_id
26
+ def self.app_id
27
+ @app_id || raise_unconfigured_exception
28
+ end
29
+
30
+ # when configuration is missing, raise exception
31
+ def self.raise_unconfigured_exception
32
+ raise NotConfigured.new("No configuration provided for Facebooker2. Either set the app_id and secret or call Facebooker2.load_facebooker_yaml in an initializer")
33
+ end
34
+
35
+ # load configuration from hash
36
+ def self.configuration=(hash)
37
+ self.api_key = hash[:api_key]
38
+ self.secret = hash[:secret]
39
+ self.app_id = hash[:app_id]
40
+ end
41
+
42
+ # read configuration from yaml config file
43
+ def self.load_facebooker_yaml
44
+ config = YAML.load(ERB.new(File.read(File.join(::Rails.root,"config","facebooker.yml"))).result)[::Rails.env]
45
+ raise NotConfigured.new("Unable to load configuration for #{::Rails.env} from facebooker.yml. Is it set up?") if config.nil?
46
+ self.configuration = config.with_indifferent_access
47
+ end
48
+
49
+ # flexible access to facebook_id of user from several possible object types
50
+ def self.cast_to_facebook_id(object)
51
+ if object.kind_of?(Mogli::Profile)
52
+ object.id
53
+ elsif object.respond_to?(:facebook_id)
54
+ object.facebook_id
55
+ else
56
+ object
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,7 @@
1
+ module Facebooker2
2
+ ###
3
+ # Exception raised when configuration is unable to be loaded from facebooker.yml
4
+ #
5
+ class NotConfigured < Exception
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module Facebooker2
2
+ module Rails
3
+ end
4
+ end
@@ -0,0 +1,131 @@
1
+ require "digest/md5"
2
+ require "hmac-sha2"
3
+ require "ruby-debug"
4
+
5
+ module Facebooker2
6
+ module Rails
7
+ module Controller
8
+
9
+ # load required helpers
10
+ def self.included(controller)
11
+ controller.helper Facebooker2::Rails::Helpers
12
+ controller.helper_method :current_facebook_user
13
+ controller.helper_method :current_facebook_client
14
+ controller.helper_method :facebook_params
15
+ end
16
+
17
+ #
18
+ def current_facebook_user
19
+ fetch_client_and_user
20
+ @_current_facebook_user
21
+ end
22
+
23
+ #
24
+ def current_facebook_client
25
+ fetch_client_and_user
26
+ @_current_facebook_client
27
+ end
28
+
29
+ #
30
+ def fetch_client_and_user
31
+ return if @_fb_user_fetched
32
+ fetch_client_and_user_from_cookie
33
+ fetch_client_and_user_from_signed_request unless @_current_facebook_client
34
+ @_fb_user_fetched = true
35
+ end
36
+
37
+ #
38
+ def fetch_client_and_user_from_cookie
39
+ app_id = Facebooker2.app_id
40
+ if (hash_data = fb_cookie_hash_for_app_id(app_id)) and
41
+ fb_cookie_signature_correct?(fb_cookie_hash_for_app_id(app_id),Facebooker2.secret)
42
+ fb_create_user_and_client(hash_data["access_token"],hash_data["expires"],hash_data["uid"])
43
+ end
44
+ end
45
+
46
+ #
47
+ def fb_create_user_and_client(token,expires,userid)
48
+ client = Mogli::Client.new(token,expires.to_i)
49
+ user = Mogli::User.new(:id=>userid)
50
+ fb_sign_in_user_and_client(user,client)
51
+ end
52
+
53
+ # cache current facebook user and current facebook client
54
+ def fb_sign_in_user_and_client(user,client)
55
+ user.client = client
56
+ @_current_facebook_user = user
57
+ @_current_facebook_client = client
58
+ @_fb_user_fetched = true
59
+ end
60
+
61
+ #
62
+ def fb_cookie_hash_for_app_id(app_id)
63
+ return nil unless fb_cookie_for_app_id?(app_id)
64
+ hash={}
65
+ data = fb_cookie_for_app_id(app_id).gsub(/"/,"")
66
+ data.split("&").each do |str|
67
+ parts = str.split("=")
68
+ hash[parts.first] = parts.last
69
+ end
70
+ hash
71
+ end
72
+
73
+ #
74
+ def fb_cookie_for_app_id?(app_id)
75
+ !fb_cookie_for_app_id(app_id).nil?
76
+ end
77
+
78
+ #
79
+ def fb_cookie_for_app_id(app_id)
80
+ cookies["fbs_#{app_id}"]
81
+ end
82
+
83
+ #
84
+ def fb_cookie_signature_correct?(hash,secret)
85
+ sorted_keys = hash.keys.reject {|k| k=="sig"}.sort
86
+ test_string = ""
87
+ sorted_keys.each do |key|
88
+ test_string += "#{key}=#{hash[key]}"
89
+ end
90
+ test_string += secret
91
+ Digest::MD5.hexdigest(test_string) == hash["sig"]
92
+ end
93
+
94
+ #
95
+ def fb_signed_request_json(encoded)
96
+ chars_to_add = 4-(encoded.size % 4)
97
+ encoded += ("=" * chars_to_add)
98
+ Base64.decode64(encoded)
99
+ end
100
+
101
+ # cached access to facebook params
102
+ def facebook_params
103
+ @facebook_params ||= fb_load_facebook_params
104
+ end
105
+
106
+ #
107
+ def fb_load_facebook_params
108
+ return {} if params[:signed_request].blank?
109
+ sig,encoded_json = params[:signed_request].split(".")
110
+ return {} unless fb_signed_request_sig_valid?(sig,encoded_json)
111
+ ActiveSupport::JSON.decode(fb_signed_request_json(encoded_json)).with_indifferent_access
112
+ end
113
+
114
+ #
115
+ def fb_signed_request_sig_valid?(sig,encoded)
116
+ base64 = Base64.encode64(HMAC::SHA256.digest(Facebooker2.secret,encoded))
117
+ #now make the url changes that facebook makes
118
+ url_escaped_base64 = base64.gsub(/=*\n?$/,"").tr("+/","-_")
119
+ sig == url_escaped_base64
120
+ end
121
+
122
+ #
123
+ def fetch_client_and_user_from_signed_request
124
+ if facebook_params[:oauth_token]
125
+ fb_create_user_and_client(facebook_params[:oauth_token],facebook_params[:expires],facebook_params[:user_id])
126
+ end
127
+ end
128
+
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,38 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ include FacebookConnect
5
+ include Javascript
6
+ include RequestForms
7
+ include User
8
+
9
+ # converts all values of hash to strings
10
+ def fb_stringify_vals(hash)
11
+ result={}
12
+ hash.each do |key,value|
13
+ result[key]=value.to_s
14
+ end
15
+ result
16
+ end
17
+
18
+ # transforms keys based on supplied transformation hash
19
+ def fb_transform_keys(options,transformation_hash)
20
+ new_hash = {}
21
+ options.each do |key,value|
22
+ new_key = transformation_hash[key]||key
23
+ new_hash[new_key]=value
24
+ end
25
+ new_hash
26
+ end
27
+
28
+ FB_ALWAYS_VALID_OPTION_KEYS = [:class, :style]
29
+
30
+ # asserts that keys of a hash are included in a supplied list of valid keys
31
+ def fb_assert_valid_keys(options,*valid_keys)
32
+ unknown_keys = options.keys - [valid_keys + FB_ALWAYS_VALID_OPTION_KEYS].flatten
33
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,57 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module FacebookConnect
5
+
6
+ ###
7
+ # Render an <fb:login-button> element, similar to
8
+ # fb_login_button. Adds a js redirect to the onlogin event via rjs.
9
+ #
10
+ # ==== Examples
11
+ #
12
+ # fb_login_and_redirect '/other_page'
13
+ # => <fb:login-button onlogin="window.location.href = &quot;/other_page&quot;;"></fb:login-button>
14
+ #
15
+ # Like #fb_login_button, this also supports the :text option
16
+ #
17
+ # fb_login_and_redirect '/other_page', :text => "Login with Facebook", :v => '2'
18
+ # => <fb:login-button onlogin="window.location.href = &quot;/other_page&quot;;" v="2">Login with Facebook</fb:login-button>
19
+ #
20
+ def fb_login_and_redirect(url, options = {})
21
+ js = update_page do |page|
22
+ page.redirect_to url
23
+ end
24
+ text = options.delete(:text)
25
+ content_tag("fb:login-button",text,options.merge(:onlogin=>js)).html_safe
26
+ end
27
+
28
+ ###
29
+ #
30
+ #
31
+ def fb_login(options = {},&proc)
32
+ js = capture(&proc)
33
+ text = options.delete(:text)
34
+ concat(content_tag("fb:login-button",text,options.merge(:onlogin=>js)).html_safe)
35
+ end
36
+
37
+ ###
38
+ # Logs the user out of facebook and redirects to the given URL
39
+ # args are passed to the call to link_to_function
40
+ #
41
+ def fb_logout_link(text,url,*args)
42
+ function= "FB.logout(function() {window.location.href = '#{url}';})"
43
+ link_to_function text, function, *args
44
+ end
45
+
46
+ ###
47
+ #
48
+ #
49
+ def fb_server_fbml(style=nil,&proc)
50
+ style_string=" style=\"#{style}\"" if style
51
+ content = capture(&proc)
52
+ concat("<fb:serverFbml#{style_string}><script type='text/fbml'>#{content}</script></fb:serverFbml>".html_safe)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,43 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module Javascript
5
+ ###
6
+ #
7
+ #
8
+ def fb_connect_async_js(app_id=Facebooker2.app_id,options={},&proc)
9
+ opts = Hash.new(true).merge!(options)
10
+ cookie = opts[:cookie]
11
+ status = opts[:status]
12
+ xfbml = opts[:xfbml]
13
+ locale = options[:locale] || "en_US"
14
+ extra_js = capture(&proc) if block_given?
15
+ js = <<-JAVASCRIPT
16
+ <script>
17
+ window.fbAsyncInit = function() {
18
+ FB.init({
19
+ appId : '#{app_id}',
20
+ status : #{status}, // check login status
21
+ cookie : #{cookie}, // enable cookies to allow the server to access the session
22
+ xfbml : #{xfbml} // parse XFBML
23
+ });
24
+ #{extra_js}
25
+ };
26
+
27
+ (function() {
28
+ var s = document.createElement('div');
29
+ s.setAttribute('id','fb-root');
30
+ document.documentElement.getElementsByTagName("body")[0].appendChild(s);
31
+ var e = document.createElement('script');
32
+ e.src = document.location.protocol + '//connect.facebook.net/#{locale}/all.js';
33
+ e.async = true;
34
+ s.appendChild(e);
35
+ }());
36
+ </script>
37
+ JAVASCRIPT
38
+ js.html_safe
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module RequestForms
5
+ ###
6
+ # http://developers.facebook.com/docs/reference/fbml/req-choice
7
+ # Facebook has planned to deprecate this tag
8
+ # Specifies a button to be shown at the bottom of a request on the user's requests page.
9
+ #
10
+ def fb_req_choice(label,url)
11
+ tag "fb:req-choice",:label=>label,:url=>url
12
+ end
13
+
14
+ ###
15
+ # Creates a form that sends requests to the selected users.
16
+ # The form is submitted after the user confirms the sending of the request.
17
+ #
18
+ def fb_request_form(type,url,message,options={},&block)
19
+ content = capture(&block)
20
+ concat(content_tag("fb:request-form", content.to_s + fb_forgery_protection_token_tag,
21
+ {:action=>url,:method=>"post",:invite=>true,:type=>type,:content=>message}.merge(options)))
22
+ end
23
+
24
+ ###
25
+ # This is a nearly full-page interface intended to be used on canvas pages to allow the
26
+ # user to send a "large" number of requests or invitations (where "large" is generally
27
+ # some number more than 4). This tag must be used inside an fb:request-form tag.
28
+ #
29
+ def fb_multi_friend_selector(message,options={},&block)
30
+ options = fb_stringify_vals({:showborder=>false,:actiontext=>message,:max=>20}.merge(options.dup))
31
+ tag("fb:multi-friend-selector",options)
32
+ end
33
+
34
+ private
35
+ ###
36
+ # when forgery protection is enabled, add forgery protection hidden input
37
+ #
38
+ def fb_forgery_protection_token_tag
39
+ unless protect_against_forgery?
40
+ ''
41
+ else
42
+ tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module User
5
+ FB_NAME_OPTION_KEYS_TO_TRANSFORM = {:first_name_only => :firstnameonly,
6
+ :last_name_only => :lastnameonly,
7
+ :show_network => :shownetwork,
8
+ :use_you => :useyou,
9
+ :if_cant_see => :ifcantsee,
10
+ :subject_id => :subjectid}
11
+
12
+ FB_NAME_VALID_OPTION_KEYS = [:firstnameonly, :linked, :lastnameonly, :possessive, :reflexive,
13
+ :shownetwork, :useyou, :ifcantsee, :capitalize, :subjectid]
14
+
15
+ FB_PROFILE_PIC_OPTION_KEYS_TO_TRANSFORM = {:facebook_logo => 'facebook-logo'}
16
+
17
+ FB_PROFILE_PIC_VALID_OPTION_KEYS = [:size, :linked, 'facebook-logo', :width, :height]
18
+
19
+ VALID_FB_PROFILE_PIC_SIZES = [:thumb, :small, :normal, :square]
20
+
21
+ ###
22
+ # Render an fb:name tag for the given user
23
+ # This renders the name of the user specified. You can use this tag as both subject and object of
24
+ # a sentence. <em> See </em> http://wiki.developers.facebook.com/index.php/Fb:name for full description.
25
+ # Use this tag on FBML pages instead of retrieving the user's info and rendering the name explicitly.
26
+ #
27
+ def fb_name(user, options={})
28
+ options = fb_transform_keys(options,FB_NAME_OPTION_KEYS_TO_TRANSFORM)
29
+ fb_assert_valid_keys(options, FB_NAME_VALID_OPTION_KEYS)
30
+ options.merge!(:uid => Facebooker2.cast_to_facebook_id(user))
31
+ content_tag("fb:name",nil, fb_stringify_vals(options))
32
+ end
33
+
34
+ ###
35
+ # Render an fb:profile-pic tag for the given user
36
+ # <em> See </em> http://developers.facebook.com/docs/reference/fbml/profile-pic for full description.
37
+ #
38
+ def fb_profile_pic(user, options={})
39
+ options = options.dup
40
+ validate_fb_profile_pic_size(options)
41
+ options = fb_transform_keys(options,FB_PROFILE_PIC_OPTION_KEYS_TO_TRANSFORM)
42
+ fb_assert_valid_keys(options,FB_PROFILE_PIC_VALID_OPTION_KEYS)
43
+ options.merge!(:uid => Facebooker2.cast_to_facebook_id(user))
44
+ content_tag("fb:profile-pic", nil,fb_stringify_vals(options))
45
+ end
46
+
47
+ private
48
+ ###
49
+ # ensures that requested profile pic size is valid
50
+ #
51
+ def validate_fb_profile_pic_size(options)
52
+ if options.has_key?(:size) && !VALID_FB_PROFILE_PIC_SIZES.include?(options[:size].to_sym)
53
+ raise(ArgumentError, "Unknown value for size: #{options[:size]}")
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ryw-facebooker2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 8118013
5
+ prerelease: true
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 5
10
+ - x2
11
+ version: 0.0.5.x2
12
+ platform: ruby
13
+ authors:
14
+ - Ryan Walker
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-08-22 00:00:00 -04:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: mogli
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 7
31
+ segments:
32
+ - 0
33
+ - 0
34
+ - 12
35
+ version: 0.0.12
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: ruby-hmac
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ description: Facebook Connect integration library for ruby and rails (for Rspec2 + Rails3)
53
+ email: ry@anotherventure.com.com
54
+ executables: []
55
+
56
+ extensions: []
57
+
58
+ extra_rdoc_files: []
59
+
60
+ files:
61
+ - lib/facebooker2/not_configured.rb
62
+ - lib/facebooker2/rails/controller.rb
63
+ - lib/facebooker2/rails/helpers/facebook_connect.rb
64
+ - lib/facebooker2/rails/helpers/javascript.rb
65
+ - lib/facebooker2/rails/helpers/request_forms.rb
66
+ - lib/facebooker2/rails/helpers/user.rb
67
+ - lib/facebooker2/rails/helpers.rb
68
+ - lib/facebooker2/rails.rb
69
+ - lib/facebooker2.rb
70
+ has_rdoc: true
71
+ homepage: http://github.com/ryw/facebooker2
72
+ licenses: []
73
+
74
+ post_install_message:
75
+ rdoc_options: []
76
+
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">"
92
+ - !ruby/object:Gem::Version
93
+ hash: 25
94
+ segments:
95
+ - 1
96
+ - 3
97
+ - 1
98
+ version: 1.3.1
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.7
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Facebook Connect integration library for ruby and rails (for Rspec2 + Rails3)
106
+ test_files: []
107
+