djanowski-facebooker 1.0.7 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,5 +1,6 @@
1
- === x.x.x / 2008-xx-xx
1
+ === x.x.x / 2009-xx-xx
2
2
 
3
+ * Modified fql_query to return results as Hashes as a last resort [Alan Larkin]
3
4
  * fixed typo in set app properties parser [Andrew Grim, shane]
4
5
  * Removed actor_id param from templatized feed [shane]
5
6
  * Added admin.get_allocation [shane]
data/Manifest.txt CHANGED
@@ -75,6 +75,7 @@ lib/facebooker/rails/facebook_form_builder.rb
75
75
  lib/facebooker/rails/facebook_pretty_errors.rb
76
76
  lib/facebooker/rails/facebook_request_fix.rb
77
77
  lib/facebooker/rails/facebook_session_handling.rb
78
+ lib/facebooker/rails/facebook_url_helper.rb
78
79
  lib/facebooker/rails/facebook_url_rewriting.rb
79
80
  lib/facebooker/rails/helpers.rb
80
81
  lib/facebooker/rails/helpers/fb_connect.rb
data/README.txt CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- Facebooker is a Ruby wrapper over the Facebook[http://facebook.com] {REST API}[http://developer.facebook.com]. Its goals are:
7
+ Facebooker is a Ruby wrapper over the Facebook[http://facebook.com] {REST API}[http://wiki.developers.facebook.com/index.php/API]. Its goals are:
8
8
 
9
9
  * Idiomatic Ruby
10
10
  * No dependencies outside of the Ruby standard library (This is true with Rails 2.1. Previous Rails versions require the JSON gem)
@@ -55,6 +55,22 @@ Your application users will need to have added the application in facebook to ac
55
55
 
56
56
  to your application controller.
57
57
 
58
+ == using MemCache session
59
+
60
+ Facebook uses some non alphanum characters in the session identifier which interfere with memcache stored sessions. If you want to use MemCache for storing sessions, you can override the valid session id method on memcache by placing the following code in an initializer:
61
+
62
+ # add - as an okay key
63
+ class CGI
64
+ class Session
65
+ class MemCacheStore
66
+ def check_id(id) #:nodoc:#
67
+ /[^0-9a-zA-Z\-\._]+/ =~ id.to_s ? false : true
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+
58
74
  == LICENSE:
59
75
 
60
76
  (The MIT License)
@@ -1,6 +1,8 @@
1
1
  # The api key, secret key, and canvas page name are required to get started
2
2
  # Tunnel configuration is only needed if you are going to use the facebooker:tunnel Rake tasks
3
3
  # Your callback url in Facebook should be set to http://public_host:public_port
4
+ # If you're building a Facebook connect site,
5
+ # change the value of set_asset_host_to_callback_url to false
4
6
  # To develop for the new profile design, add the following key..
5
7
  # api: new
6
8
  # remove the key or set it to anything else to use the old facebook design.
@@ -12,6 +14,7 @@ development:
12
14
  canvas_page_name:
13
15
  callback_url:
14
16
  pretty_errors: true
17
+ set_asset_host_to_callback_url: true
15
18
  tunnel:
16
19
  public_host_username:
17
20
  public_host:
@@ -23,6 +26,7 @@ test:
23
26
  secret_key:
24
27
  canvas_page_name:
25
28
  callback_url:
29
+ set_asset_host_to_callback_url: true
26
30
  tunnel:
27
31
  public_host_username:
28
32
  public_host:
@@ -33,7 +37,8 @@ production:
33
37
  api_key:
34
38
  secret_key:
35
39
  canvas_page_name:
36
- callback_url:
40
+ callback_url:
41
+ set_asset_host_to_callback_url: true
37
42
  tunnel:
38
43
  public_host_username:
39
44
  public_host:
data/lib/facebooker.rb CHANGED
@@ -19,37 +19,7 @@ end
19
19
  require 'zlib'
20
20
  require 'digest/md5'
21
21
 
22
- require 'facebooker/batch_request'
23
- require 'facebooker/feed'
24
- require 'facebooker/logging'
25
- require 'facebooker/model'
26
- require 'facebooker/parser'
27
- require 'facebooker/service'
28
- require 'facebooker/server_cache'
29
- require 'facebooker/data'
30
- require 'facebooker/admin'
31
- require 'facebooker/session'
32
- require 'facebooker/version'
33
- require 'facebooker/models/location'
34
- require 'facebooker/models/affiliation'
35
- require 'facebooker/models/album'
36
- require 'facebooker/models/education_info'
37
- require 'facebooker/models/work_info'
38
- require 'facebooker/models/event'
39
- require 'facebooker/models/group'
40
- require 'facebooker/models/notifications'
41
- require 'facebooker/models/page'
42
- require 'facebooker/models/photo'
43
- require 'facebooker/models/cookie'
44
- require 'facebooker/models/applicationproperties'
45
- require 'facebooker/models/tag'
46
- require 'facebooker/models/user'
47
- require 'facebooker/models/info_item'
48
- require 'facebooker/models/info_section'
49
- require 'facebooker/adapters/adapter_base'
50
- require 'facebooker/adapters/facebook_adapter'
51
- require 'facebooker/adapters/bebo_adapter'
52
- require 'facebooker/models/friend_list'
22
+
53
23
 
54
24
  module Facebooker
55
25
 
@@ -66,8 +36,12 @@ module Facebooker
66
36
  ENV['FACEBOOK_SECRET_KEY'] = facebooker['secret_key']
67
37
  ENV['FACEBOOKER_RELATIVE_URL_ROOT'] = facebooker['canvas_page_name']
68
38
  ENV['FACEBOOKER_API'] = facebooker['api']
39
+ if facebooker.has_key?('set_asset_host_to_callback_url')
40
+ Facebooker.set_asset_host_to_callback_url = facebooker['set_asset_host_to_callback_url']
41
+ end
42
+ Facebooker.timeout = facebooker['timeout']
69
43
  if Object.const_defined?("ActionController")
70
- ActionController::Base.asset_host = facebooker['callback_url'] if(ActionController::Base.asset_host.blank?)
44
+ ActionController::Base.asset_host = facebooker['callback_url'] if(ActionController::Base.asset_host.blank?) && Facebooker.set_asset_host_to_callback_url
71
45
  end
72
46
  @facebooker_configuration = facebooker
73
47
  end
@@ -102,7 +76,29 @@ module Facebooker
102
76
  current_adapter.is_for?(application_container)
103
77
  end
104
78
 
105
-
79
+ def set_asset_host_to_callback_url=(val)
80
+ @set_asset_host_to_callback_url=val
81
+ end
82
+
83
+ def set_asset_host_to_callback_url
84
+ @set_asset_host_to_callback_url.nil? ? true : @set_asset_host_to_callback_url
85
+ end
86
+
87
+ def use_curl=(val)
88
+ @use_curl=val
89
+ end
90
+
91
+ def use_curl?
92
+ @use_curl
93
+ end
94
+
95
+ def timeout=(val)
96
+ @timeout = val.to_i
97
+ end
98
+
99
+ def timeout
100
+ @timeout
101
+ end
106
102
 
107
103
  [:api_key,:secret_key, :www_server_base_url,:login_url_base,:install_url_base,:api_rest_path,:api_server_base,:api_server_base_url,:canvas_server_base].each do |delegated_method|
108
104
  define_method(delegated_method){ return current_adapter.send(delegated_method)}
@@ -141,3 +137,35 @@ module Facebooker
141
137
  end
142
138
  end
143
139
  end
140
+
141
+ require 'facebooker/batch_request'
142
+ require 'facebooker/feed'
143
+ require 'facebooker/logging'
144
+ require 'facebooker/model'
145
+ require 'facebooker/parser'
146
+ require 'facebooker/service'
147
+ require 'facebooker/server_cache'
148
+ require 'facebooker/data'
149
+ require 'facebooker/admin'
150
+ require 'facebooker/session'
151
+ require 'facebooker/version'
152
+ require 'facebooker/models/location'
153
+ require 'facebooker/models/affiliation'
154
+ require 'facebooker/models/album'
155
+ require 'facebooker/models/education_info'
156
+ require 'facebooker/models/work_info'
157
+ require 'facebooker/models/event'
158
+ require 'facebooker/models/group'
159
+ require 'facebooker/models/notifications'
160
+ require 'facebooker/models/page'
161
+ require 'facebooker/models/photo'
162
+ require 'facebooker/models/cookie'
163
+ require 'facebooker/models/applicationproperties'
164
+ require 'facebooker/models/tag'
165
+ require 'facebooker/models/user'
166
+ require 'facebooker/models/info_item'
167
+ require 'facebooker/models/info_section'
168
+ require 'facebooker/adapters/adapter_base'
169
+ require 'facebooker/adapters/facebook_adapter'
170
+ require 'facebooker/adapters/bebo_adapter'
171
+ require 'facebooker/models/friend_list'
@@ -10,7 +10,7 @@ module Facebooker
10
10
  include Model
11
11
  attr_accessor :message, :time, :status_id
12
12
  end
13
- FIELDS = [:status, :political, :pic_small, :name, :quotes, :is_app_user, :tv, :profile_update_time, :meeting_sex, :hs_info, :timezone, :relationship_status, :hometown_location, :about_me, :wall_count, :significant_other_id, :pic_big, :music, :uid, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email]
13
+ FIELDS = [:status, :political, :pic_small, :name, :quotes, :is_app_user, :tv, :profile_update_time, :meeting_sex, :hs_info, :timezone, :relationship_status, :hometown_location, :about_me, :wall_count, :significant_other_id, :pic_big, :music, :uid, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email,:email_hashes]
14
14
  STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url]
15
15
  attr_accessor :id, :session
16
16
  populating_attr_accessor *FIELDS
@@ -86,7 +86,9 @@ module Facebooker
86
86
 
87
87
  #use __blank instead of nil so that this is cached
88
88
  cache_key = flid||"__blank"
89
- @friends_hash[cache_key] ||= @session.post('facebook.friends.get', (flid.nil? ? {} : {:flid => flid})).map do |uid|
89
+ options = {:uid=>@id}
90
+ options[:flid] = flid unless flid.nil?
91
+ @friends_hash[cache_key] ||= @session.post('facebook.friends.get', options,false).map do |uid|
90
92
  User.new(uid, @session)
91
93
  end
92
94
  @friends_hash[cache_key]
@@ -169,8 +171,35 @@ module Facebooker
169
171
  session.get_photos(nil, nil, profile_pic_album_id)
170
172
  end
171
173
 
172
- def upload_photo(multipart_post_file)
173
- Photo.from_hash(session.post_file('facebook.photos.upload', {nil => multipart_post_file}))
174
+ # Upload a photo to the user's profile.
175
+ #
176
+ # In your view, create a multipart form that posts directly to your application (not through canvas):
177
+ #
178
+ # <% form_tag photos_url(:canvas => false), :html => {:multipart => true, :promptpermission => 'photo_upload'} do %>
179
+ # Photo: <%= file_field_tag 'photo' %>
180
+ # Caption: <%= text_area_tag 'caption' %>
181
+ # <%= submit_tag 'Upload Photo', :class => 'inputsubmit' %>
182
+ # <% end %>
183
+ #
184
+ # And in your controller:
185
+ #
186
+ # class PhotosController < ApplicationController
187
+ # def create
188
+ # file = Net::HTTP::MultipartPostFile.new(
189
+ # params[:photo].original_filename,
190
+ # params[:photo].content_type,
191
+ # params[:photo].read
192
+ # )
193
+ #
194
+ # @photo = facebook_session.user.upload_photo(file, :caption => params[:caption])
195
+ # redirect_to photos_url(:canvas => true)
196
+ # end
197
+ # end
198
+ #
199
+ # Options correspond to http://wiki.developers.facebook.com/index.php/Photos.upload
200
+ def upload_photo(multipart_post_file, options = {})
201
+ Photo.from_hash(session.post_file('facebook.photos.upload',
202
+ options.merge(nil => multipart_post_file)))
174
203
  end
175
204
 
176
205
  def profile_fbml
@@ -73,9 +73,12 @@ module Facebooker
73
73
  end
74
74
 
75
75
  def clear_fb_cookies!
76
- fb_cookie_names.each {|name| cookies[name] = nil }
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
77
80
  end
78
-
81
+
79
82
  def fb_cookie_prefix
80
83
  Facebooker.api_key+"_"
81
84
  end
@@ -190,7 +193,11 @@ module Facebooker
190
193
  end
191
194
 
192
195
  def request_comes_from_facebook?
193
- request_is_for_a_facebook_canvas? || request_is_facebook_ajax?
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?
194
201
  end
195
202
 
196
203
  def request_is_for_a_facebook_canvas?
@@ -0,0 +1,191 @@
1
+ # Extends the ActionView::Helpers::UrlHelper module. See it for details on
2
+ # the usual url helper methods: url_for, link_to, button_to, etc.
3
+ #
4
+ # Mostly, the changes sanitize javascript into facebook javascript.
5
+ # It sanitizes link_to solely by altering the private methods:
6
+ # convert_options_to_javascript!, confirm_javascript_function, and
7
+ # method_javascript_function. For button_to, it alters button_to
8
+ # itself, as well as confirm_javascript_function. No other methods
9
+ # need to be changed because of Facebook javascript.
10
+ #
11
+ # For button_to and link_to, adds alternate confirm options for facebook.
12
+ # ==== Options
13
+ # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
14
+ # prompt with the question specified.
15
+ #
16
+ # Example:
17
+ # # Generates: <a href="http://rubyforge.org/projects/facebooker" onclick="
18
+ # # var dlg = new Dialog().showChoice('Please Confirm', 'Go to Facebooker?').setStyle();
19
+ # # var a=this;dlg.onconfirm = function() {
20
+ # # document.setLocation(a.getHref());
21
+ # # }; return false;">Facebooker</a>
22
+ # link_to("Facebooker", "http://rubyforge.org/projects/facebooker", :confirm=>"Go to Facebooker?")
23
+ #
24
+ # Alternatively, options[:confirm] may be specified.
25
+ # See the Facebook page http://wiki.developers.facebook.com/index.php/FBJS.
26
+ # These options are:
27
+ # <tt>:title</tt>:: Specifies the title of the Facebook dialog. Default is "Please Confirm".
28
+ # <tt>:content</tt>:: Specifies the title of the Facebook dialog. Default is "Are you sure?".
29
+ #
30
+ # Example:
31
+ # # Generates: <a href="http://rubyforge.org/projects/facebooker" onclick="
32
+ # # var dlg = new Dialog().showChoice('the page says:', 'Go to Facebooker?').setStyle();
33
+ # # var a=this;dlg.onconfirm = function() {
34
+ # # document.setLocation(a.getHref());
35
+ # # }; return false;">Facebooker</a>
36
+ # link_to("Facebooker", "http://rubyforge.org/projects/facebooker", :confirm=>{:title=>"the page says:", :content=>"Go to Facebooker?"})
37
+ #
38
+ # Any other options passed are assumed to be css styles.
39
+ # Again, see the Facebook page http://wiki.developers.facebook.com/index.php/FBJS.
40
+ #
41
+ # Example:
42
+ # # Generates: <a href="http://rubyforge.org/projects/facebooker" onclick="
43
+ # # var dlg = new Dialog().showChoice('the page says:', 'Are you sure?').setStyle({color: 'pink', width: '200px'});
44
+ # # var a=this;dlg.onconfirm = function() {
45
+ # # document.setLocation(a.getHref());
46
+ # # }; return false;">Facebooker</a>
47
+ # link_to("Facebooker", "http://rubyforge.org/projects/facebooker", :confirm=>{:title=>"the page says:, :color=>"pink", :width=>"200px"})
48
+ module ActionView
49
+ module Helpers
50
+ module UrlHelper
51
+ # Alters one and only one line of the Rails button_to. See below.
52
+ def button_to_with_facebooker(name, options={}, html_options = {})
53
+ if !request_comes_from_facebook?
54
+ button_to_without_facebooker(name,options,html_options)
55
+ else
56
+ html_options = html_options.stringify_keys
57
+ convert_boolean_attributes!(html_options, %w( disabled ))
58
+
59
+ method_tag = ''
60
+ if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
61
+ method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
62
+ end
63
+
64
+ form_method = method.to_s == 'get' ? 'get' : 'post'
65
+
66
+ request_token_tag = ''
67
+ if form_method == 'post' && protect_against_forgery?
68
+ request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
69
+ end
70
+
71
+ if confirm = html_options.delete("confirm")
72
+ # this line is the only change => html_options["onclick"] = "return #{confirm_javascript_function(confirm)}"
73
+ html_options["onclick"] = "#{confirm_javascript_function(confirm, 'a.getForm().submit();')}return false;"
74
+ end
75
+
76
+ url = options.is_a?(String) ? options : self.url_for(options)
77
+ name ||= url
78
+
79
+ html_options.merge!("type" => "submit", "value" => name)
80
+
81
+ "<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +
82
+ method_tag + tag("input", html_options) + request_token_tag + "</div></form>"
83
+ end
84
+ end
85
+
86
+ alias_method_chain :button_to, :facebooker
87
+
88
+ private
89
+
90
+ # Altered to throw an error on :popup and sanitize the javascript
91
+ # for Facebook.
92
+ def convert_options_to_javascript_with_facebooker!(html_options, url ='')
93
+ if !request_comes_from_facebook?
94
+ convert_options_to_javascript_without_facebooker!(html_options,url)
95
+ else
96
+ confirm, popup = html_options.delete("confirm"), html_options.delete("popup")
97
+
98
+ method, href = html_options.delete("method"), html_options['href']
99
+
100
+ html_options["onclick"] = case
101
+ when popup
102
+ raise ActionView::ActionViewError, "You can't use :popup"
103
+ when method # or maybe (confirm and method)
104
+ "#{method_javascript_function(method, url, href, confirm)}return false;"
105
+ when confirm # and only confirm
106
+ "#{confirm_javascript_function(confirm)}return false;"
107
+ else
108
+ html_options["onclick"]
109
+ end
110
+ end
111
+ end
112
+
113
+ alias_method_chain :convert_options_to_javascript!, :facebooker
114
+
115
+
116
+ # Overrides a private method that link_to calls via convert_options_to_javascript! and
117
+ # also, button_to calls directly. For Facebook, confirm can be a hash of options to
118
+ # stylize the Facebook dialog. Takes :title, :content, :style options. See
119
+ # the Facebook page http://wiki.developers.facebook.com/index.php/FBJS for valid
120
+ # style formats like "color: 'black', background: 'white'" or like "'color','black'".
121
+ #
122
+ # == Examples ==
123
+ #
124
+ # link_to("Facebooker", "http://rubyforge.org/projects/facebooker", :confirm=>"Go to Facebooker?")
125
+ # link_to("Facebooker", "http://rubyforge.org/projects/facebooker", :confirm=>{:title=>"the page says:, :content=>"Go to Facebooker?"})
126
+ # link_to("Facebooker", "http://rubyforge.org/projects/facebooker", :confirm=>{:title=>"the page says:, :content=>"Go to Facebooker?", :color=>"pink"})
127
+ def confirm_javascript_function_with_facebooker(confirm, fun = nil)
128
+ if !request_comes_from_facebook?
129
+ confirm_javascript_function_without_facebooker(confirm)
130
+ else
131
+ if(confirm.is_a?(Hash))
132
+ confirm_options = confirm.stringify_keys
133
+ title = confirm_options.delete("title") || "Please Confirm"
134
+ content = confirm_options.delete("content") || "Are you sure?"
135
+ style = confirm_options.empty? ? "" : convert_options_to_css(confirm_options)
136
+ else
137
+ title,content,style = 'Please Confirm', confirm, ""
138
+ end
139
+
140
+ "var dlg = new Dialog().showChoice('#{escape_javascript(title.to_s)}','#{escape_javascript(content.to_s)}').setStyle(#{style});"+
141
+ "var a=this;dlg.onconfirm = function() { #{fun ? fun : 'document.setLocation(a.getHref());'} };"
142
+ end
143
+ end
144
+
145
+ alias_method_chain :confirm_javascript_function, :facebooker
146
+
147
+ def convert_options_to_css(options)
148
+ key_pair = options.shift
149
+ style = "{#{key_pair[0]}: '#{key_pair[1]}'"
150
+ for key in options.keys
151
+ style << ", #{key}: '#{options[key]}'"
152
+ end
153
+ style << "}"
154
+ end
155
+
156
+ # Dynamically creates a form for link_to with method. Calls confirm_javascript_function if and
157
+ # only if (confirm && method) for link_to
158
+ def method_javascript_function_with_facebooker(method, url = '', href = nil, confirm = nil)
159
+ if !request_comes_from_facebook?
160
+ method_javascript_function_without_facebooker(method,url,href)
161
+ else
162
+ action = (href && url.size > 0) ? "'#{url}'" : 'a.getHref()'
163
+ submit_function =
164
+ "var f = document.createElement('form'); f.setStyle('display','none'); " +
165
+ "a.getParentNode().appendChild(f); f.setMethod('POST'); f.setAction(#{action});"
166
+
167
+ unless method == :post
168
+ submit_function << "var m = document.createElement('input'); m.setType('hidden'); "
169
+ submit_function << "m.setName('_method'); m.setValue('#{method}'); f.appendChild(m);"
170
+ end
171
+
172
+ if protect_against_forgery?
173
+ submit_function << "var s = document.createElement('input'); s.setType('hidden'); "
174
+ submit_function << "s.setName('#{request_forgery_protection_token}'); s.setValue('#{escape_javascript form_authenticity_token}'); f.appendChild(s);"
175
+ end
176
+ submit_function << "f.submit();"
177
+
178
+ if(confirm)
179
+ confirm_javascript_function(confirm, submit_function)
180
+ else
181
+ "var a=this;" + submit_function
182
+ end
183
+ end
184
+ end
185
+
186
+ alias_method_chain :method_javascript_function, :facebooker
187
+
188
+ end
189
+ end
190
+ end
191
+
@@ -524,20 +524,52 @@ module Facebooker
524
524
 
525
525
  #
526
526
  # Embed a discussion board named xid on the current page
527
- #
527
+ # <em>See</em http://wiki.developers.facebook.com/index.php/Fb:board for more details
528
+ # Options are:
529
+ # * canpost
530
+ # * candelete
531
+ # * canmark
532
+ # * cancreatet
533
+ # * numtopics
534
+ # * callbackurl
535
+ # * returnurl
536
+ #
528
537
  def fb_board(xid,options={})
529
538
  options = options.dup
530
- tag("fb:board",stringify_vals(options.merge(:xid=>xid)))
539
+ title = (title = options.delete(:title)) ? fb_title(title) : nil
540
+ content_tag("fb:board", title, stringify_vals(options.merge(:xid=>xid)))
531
541
  end
532
542
 
543
+ # Renders an 'Add to Profile' button
544
+ # The button allows a user to add condensed profile box to the main profile
533
545
  def fb_add_profile_section
534
546
  tag "fb:add-section-button",:section=>"profile"
535
547
  end
536
548
 
549
+ # Renders an 'Add to Info' button
550
+ # The button allows a user to add an application info section to her Info tab
537
551
  def fb_add_info_section
538
552
  tag "fb:add-section-button",:section=>"info"
539
553
  end
540
554
 
555
+ # Renders a link that, when clicked, initiates a dialog requesting the specified extended permission from the user.
556
+ #
557
+ # You can prompt a user with the following permissions:
558
+ # * email
559
+ # * offline_access
560
+ # * status_update
561
+ # * photo_upload
562
+ # * create_listing
563
+ # * create_event
564
+ # * rsvp_event
565
+ # * sms
566
+ #
567
+ # Example:
568
+ # <%= fb_prompt_permission('email', "Would you like to receive email from our application?" ) %>
569
+ #
570
+ # See http://wiki.developers.facebook.com/index.php/Fb:prompt-permission for
571
+ # more details
572
+ #
541
573
  def fb_prompt_permission(permission,message,callback=nil)
542
574
  raise(ArgumentError, "Unknown value for permission: #{permission}") unless VALID_PERMISSIONS.include?(permission.to_sym)
543
575
  args={:perms=>permission}
@@ -545,22 +577,29 @@ module Facebooker
545
577
  content_tag("fb:prompt-permission",message,args)
546
578
  end
547
579
 
580
+ # Renders an <fb:eventlink /> tag that displays the event name and links to the event's page.
548
581
  def fb_eventlink(eid)
549
582
  content_tag "fb:eventlink",nil,:eid=>eid
550
583
  end
551
584
 
585
+ # Renders an <fb:grouplink /> tag that displays the group name and links to the group's page.
552
586
  def fb_grouplink(gid)
553
587
  content_tag "fb:grouplink",nil,:gid=>gid
554
588
  end
555
589
 
590
+ # Returns the status of the user
556
591
  def fb_user_status(user,linked=true)
557
592
  content_tag "fb:user-status",nil,stringify_vals(:uid=>cast_to_facebook_id(user), :linked=>linked)
558
593
  end
559
594
 
595
+ # Renders a standard 'Share' button for the specified URL.
560
596
  def fb_share_button(url)
561
597
  content_tag "fb:share-button",nil,:class=>"url",:href=>url
562
598
  end
563
599
 
600
+ # Renders the FBML on a Facebook server inside an iframe.
601
+ #
602
+ # Meant to be used for a Facebook Connect site or an iframe application
564
603
  def fb_serverfbml(options={},&proc)
565
604
  inner = capture(&proc)
566
605
  concat(content_tag("fb:serverfbml",inner,options),&proc.binding)
@@ -174,10 +174,13 @@ module Facebooker
174
174
 
175
175
  def hashed_content(klass, method)
176
176
  publisher = setup_publisher(klass,method)
177
- Digest::MD5.hexdigest [publisher.one_line_story_templates, publisher.short_story_templates, publisher.full_story_template].to_json
177
+ # sort the Hash elements (in the short_story and full_story) before generating MD5
178
+ Digest::MD5.hexdigest [publisher.one_line_story_templates,
179
+ (publisher.short_story_templates and publisher.short_story_templates.collect{|ss| ss.to_a.sort_by{|e| e[0]}}),
180
+ (publisher.full_story_template and publisher.full_story_template.to_a.sort_by{|e| e[0]})
181
+ ].to_json
178
182
  end
179
183
 
180
-
181
184
  def template_name(klass,method)
182
185
  "#{klass.name}::#{method}"
183
186
  end
@@ -1,4 +1,10 @@
1
- require 'net/http'
1
+ begin
2
+ require 'curb'
3
+ Facebooker.use_curl = true
4
+ rescue Exception=>e
5
+ puts e
6
+ require 'net/http'
7
+ end
2
8
  require 'facebooker/parser'
3
9
  module Facebooker
4
10
  class Service
@@ -11,7 +17,7 @@ module Facebooker
11
17
  # TODO: support ssl
12
18
  def post(params)
13
19
  attempt = 0
14
- Parser.parse(params[:method], Net::HTTP.post_form(url, params))
20
+ Parser.parse(params[:method], post_form(url,params) )
15
21
  rescue Errno::ECONNRESET, EOFError
16
22
  if attempt == 0
17
23
  attempt += 1
@@ -19,13 +25,68 @@ module Facebooker
19
25
  end
20
26
  end
21
27
 
28
+ def post_form(url,params)
29
+ if Facebooker.use_curl?
30
+ post_form_with_curl(url,params)
31
+ else
32
+ post_form_with_net_http(url,params)
33
+ end
34
+ end
35
+
36
+ def post_form_with_net_http(url,params)
37
+ Net::HTTP.post_form(url, params)
38
+ end
39
+
40
+ def post_form_with_curl(url,params,multipart=false)
41
+ response = Curl::Easy.http_post(url.to_s, *to_curb_params(params)) do |c|
42
+ c.multipart_form_post = multipart
43
+ c.timeout = Facebooker.timeout
44
+ end
45
+ response.body_str
46
+ end
47
+
48
+ def post_multipart_form(url,params)
49
+ if Facebooker.use_curl?
50
+ post_form_with_curl(url,params,true)
51
+ else
52
+ post_multipart_form_with_net_http(url,params)
53
+ end
54
+ end
55
+
56
+ def post_multipart_form_with_net_http(url,params)
57
+ Net::HTTP.post_multipart_form(url, params)
58
+ end
59
+
22
60
  def post_file(params)
23
- Parser.parse(params[:method], Net::HTTP.post_multipart_form(url, params))
61
+ Parser.parse(params[:method], post_multipart_form(url, params))
24
62
  end
25
63
 
26
64
  private
27
65
  def url
28
66
  URI.parse('http://'+ @api_base + @api_path)
29
67
  end
68
+
69
+ # Net::HTTP::MultipartPostFile
70
+ def multipart_post_file?(object)
71
+ object.respond_to?(:content_type) &&
72
+ object.respond_to?(:data) &&
73
+ object.respond_to?(:filename)
74
+ end
75
+
76
+ def to_curb_params(params)
77
+ parray = []
78
+ params.each_pair do |k,v|
79
+ if multipart_post_file?(v)
80
+ # Curl doesn't like blank field names
81
+ field = Curl::PostField.file((k.blank? ? 'xxx' : k.to_s), nil, File.basename(v.filename))
82
+ field.content_type = v.content_type
83
+ field.content = v.data
84
+ parray << field
85
+ else
86
+ parray << Curl::PostField.content(k.to_s, v.to_s)
87
+ end
88
+ end
89
+ parray
90
+ end
30
91
  end
31
92
  end
@@ -178,8 +178,10 @@ module Facebooker
178
178
  Photo.from_hash(hash)
179
179
  when 'event_member'
180
180
  Event::Attendance.from_hash(hash)
181
+ else
182
+ hash
181
183
  end
182
- end
184
+ end
183
185
  end
184
186
  end
185
187
 
@@ -211,13 +213,13 @@ module Facebooker
211
213
  end
212
214
 
213
215
  def users_standard(user_ids, fields=[])
214
- post("facebook.users.getStandardInfo",:uids=>user_ids.join(","),:fields=>User.user_fields(fields)) do |users|
216
+ post("facebook.users.getStandardInfo",:uids=>user_ids.join(","),:fields=>User.standard_fields(fields)) do |users|
215
217
  users.map { |u| User.new(u)}
216
218
  end
217
219
  end
218
220
 
219
221
  def users(user_ids, fields=[])
220
- post("facebook.users.getInfo",:uids=>user_ids.join(","),:fields=>User.standard_fields(fields)) do |users|
222
+ post("facebook.users.getInfo",:uids=>user_ids.join(","),:fields=>User.user_fields(fields)) do |users|
221
223
  users.map { |u| User.new(u)}
222
224
  end
223
225
  end
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/test_helper.rb'
3
3
  class FacebookAdminTest < Test::Unit::TestCase
4
4
  def setup
5
5
  @session = Facebooker::Session.create('apikey', 'secretkey')
6
+ Facebooker.use_curl=false
6
7
  end
7
8
 
8
9
  def test_can_ask_facebook_to_set_app_properties
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/test_helper.rb'
3
3
  class FacebookCacheTest < Test::Unit::TestCase
4
4
  def setup
5
5
  @session = Facebooker::Session.create('apikey', 'secretkey')
6
+ Facebooker.use_curl=false
6
7
  end
7
8
 
8
9
  def test_can_ask_facebook_to_store_fbml_in_a_named_reference
@@ -3,6 +3,8 @@ require File.dirname(__FILE__) + '/test_helper.rb'
3
3
  class FacebookDataTest < Test::Unit::TestCase
4
4
  def setup
5
5
  @session = Facebooker::Session.create('apikey', 'secretkey')
6
+ #make sure we use net::http since that's what the tests expect
7
+ Facebooker.use_curl=false
6
8
  end
7
9
 
8
10
  def test_can_ask_facebook_to_set_a_cookies
@@ -894,7 +894,10 @@ class RailsHelperTest < Test::Unit::TestCase
894
894
  assert_equal "<fb:comments candelete=\"false\" canpost=\"true\" numposts=\"4\" optional=\"false\" xid=\"xxx\"><fb:title>TITLE</fb:title></fb:comments>", @h.fb_comments("xxx",true,false,4,:optional=>false, :title => "TITLE")
895
895
  end
896
896
  def test_fb_board
897
- assert_equal "<fb:board optional=\"false\" xid=\"xxx\" />", @h.fb_board("xxx",:optional => false)
897
+ assert_equal "<fb:board optional=\"false\" xid=\"xxx\"></fb:board>", @h.fb_board("xxx",:optional => false)
898
+ end
899
+ def test_fb_board_with_title
900
+ assert_equal "<fb:board optional=\"false\" xid=\"xxx\"><fb:title>TITLE</fb:title></fb:board>", @h.fb_board("xxx",:optional=>false, :title => "TITLE")
898
901
  end
899
902
 
900
903
  def test_fb_dashboard
data/test/session_test.rb CHANGED
@@ -8,6 +8,7 @@ class SessionTest < Test::Unit::TestCase
8
8
  ENV['FACEBOOK_SECRET_KEY'] = '7654321'
9
9
  Facebooker.current_adapter = nil
10
10
  @session = Facebooker::Session.create('whatever', 'doesnotmatterintest')
11
+ Facebooker.use_curl=false
11
12
  end
12
13
 
13
14
  def teardown
@@ -574,6 +575,31 @@ class SessionTest < Test::Unit::TestCase
574
575
  end
575
576
  end
576
577
 
578
+ class PostMethodTest < Test::Unit::TestCase
579
+
580
+ def setup
581
+ Facebooker.use_curl = true
582
+ Facebooker::Parser.stubs(:parse)
583
+ @uri = URI.parse("http://api.facebook.com/api")
584
+ @service = Facebooker::Service.new("a","b","c")
585
+ @service.stubs("url").returns(@uri)
586
+ end
587
+
588
+ def teardown
589
+ Facebooker.use_curl = false
590
+ end
591
+
592
+ def test_use_curl_makes_post_with_curl
593
+ @service.expects(:post_form_with_curl).with(@uri,{:method=>"a"})
594
+ @service.post(:method=>"a")
595
+ end
596
+
597
+ def test_use_curl_makes_post_file_use_curl_with_multipart
598
+ @service.expects(:post_form_with_curl).with(@uri,{:method=>"a"},true)
599
+ @service.post_file(:method=>"a")
600
+ end
601
+ end
602
+
577
603
  class CanvasSessionTest < Test::Unit::TestCase
578
604
  def setup
579
605
  ENV['FACEBOOK_API_KEY'] = '1234567'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: djanowski-facebooker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chad Fowler
@@ -117,6 +117,7 @@ files:
117
117
  - lib/facebooker/rails/facebook_pretty_errors.rb
118
118
  - lib/facebooker/rails/facebook_request_fix.rb
119
119
  - lib/facebooker/rails/facebook_session_handling.rb
120
+ - lib/facebooker/rails/facebook_url_helper.rb
120
121
  - lib/facebooker/rails/facebook_url_rewriting.rb
121
122
  - lib/facebooker/rails/helpers.rb
122
123
  - lib/facebooker/rails/helpers/fb_connect.rb