mmangino-facebooker 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/init.rb CHANGED
@@ -41,6 +41,22 @@ class ActionController::Routing::Route
41
41
  alias_method_chain :recognition_conditions, :facebooker
42
42
  end
43
43
 
44
+ # When making get requests, Facebook sends fb_sig parameters both in the query string
45
+ # and also in the post body. We want to ignore the query string ones because they are one
46
+ # request out of date
47
+ # We only do thise when there are POST parameters so that IFrame linkage still works
48
+ class ActionController::AbstractRequest
49
+ def query_parameters_with_facebooker
50
+ if request_parameters.blank?
51
+ query_parameters_without_facebooker
52
+ else
53
+ (query_parameters_without_facebooker||{}).reject {|key,value| key.to_s =~ /^fb_sig/}
54
+ end
55
+ end
56
+
57
+ alias_method_chain :query_parameters, :facebooker
58
+ end
59
+
44
60
  # We turn off route optimization to make named routes use our code for figuring out if they should go to the session
45
61
  # If this fails, it means we're on rails 1.2, we can ignore it
46
62
  begin
@@ -43,13 +43,18 @@ module Facebooker
43
43
  # Returns a user's events, params correspond to API call parameters (except UID):
44
44
  # http://wiki.developers.facebook.com/index.php/Events.get
45
45
  # E.g:
46
- # @user.events(:start_time => Time.now.to_i, :end_time => 1.month.from_now.to_i)
46
+ # @user.events(:start_time => Time.now, :end_time => 1.month.from_now)
47
47
  # # => Returns events betwen now and a month from now
48
48
  def events(params={})
49
- @events ||= @session.post('facebook.events.get', {:uid => self.id}.merge(params)).map do |event|
49
+ @events ||= {}
50
+ [:start_time,:end_time].compact.each do |key|
51
+ params[key] = params[key].to_i
52
+ end
53
+ # puts @events[params.to_s].nil?
54
+ @events[params.to_s] ||= @session.post('facebook.events.get', {:uid => self.id}.merge(params)).map do |event|
50
55
  Event.from_hash(event)
51
56
  end
52
- end
57
+ end
53
58
 
54
59
  #
55
60
  # Set the list of friends, given an array of User objects. If the list has been retrieved previously, will not set
@@ -219,24 +224,35 @@ module Facebooker
219
224
  end
220
225
 
221
226
  ##
222
- # Set the status of the user
223
- #
224
- # DOES NOT prepend "is" to the message
225
- #
226
- # requires extended permission.
227
+ # This DOES NOT set the status of a user on Facebook
228
+ # Use the set_status method instead
227
229
  def status=(message)
228
230
  case message
229
- when String
230
- session.post('facebook.users.setStatus',:status=>message,:status_includes_verb=>1) do |ret|
231
- ret
232
- end
233
- when Status
231
+ when String,Status
234
232
  @status = message
235
233
  when Hash
236
234
  @status = Status.from_hash(message)
237
235
  end
238
236
  end
239
237
 
238
+ ##
239
+ # Set the status for a user
240
+ # DOES NOT prepend "is" to the message
241
+ #
242
+ # requires extended permission.
243
+ def set_status(message)
244
+ self.status=message
245
+ session.post('facebook.users.setStatus',:status=>message,:status_includes_verb=>1) do |ret|
246
+ ret
247
+ end
248
+ end
249
+
250
+ ##
251
+ # Checks to see if the user has enabled the given extended permission
252
+ def has_permission?(ext_perm) # ext_perm = email, offline_access, status_update, photo_upload, create_listing, create_event, rsvp_event, sms
253
+ session.post('facebook.users.hasAppPermission',:ext_perm=>ext_perm) == "1"
254
+ end
255
+
240
256
  ##
241
257
  # Convenience method to send email to the current user
242
258
  def send_email(subject, text=nil, fbml=nil)
@@ -401,8 +401,8 @@ module Facebooker
401
401
  memo
402
402
  end
403
403
  end
404
-
405
- private
404
+
405
+ private
406
406
  def self.are_friends?(raw_value)
407
407
  if raw_value == '1'
408
408
  true
@@ -432,6 +432,12 @@ module Facebooker
432
432
  end
433
433
  end
434
434
 
435
+ class UserHasPermission < Parser
436
+ def self.process(data)
437
+ element('users_hasAppPermission_response', data).text_value
438
+ end
439
+ end
440
+
435
441
  class Errors < Parser#:nodoc:
436
442
  EXCEPTIONS = {
437
443
  1 => Facebooker::Session::UnknownError,
@@ -492,6 +498,7 @@ module Facebooker
492
498
  'facebook.users.getStandardInfo' => UserStandardInfo,
493
499
  'facebook.users.setStatus' => SetStatus,
494
500
  'facebook.users.getLoggedInUser' => GetLoggedInUser,
501
+ 'facebook.users.hasAppPermission' => UserHasPermission,
495
502
  'facebook.pages.isAdmin' => PagesIsAdmin,
496
503
  'facebook.pages.getInfo' => PagesGetInfo,
497
504
  'facebook.friends.get' => GetFriends,
@@ -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
+
data/test/user_test.rb CHANGED
@@ -15,6 +15,11 @@ class UserTest < Test::Unit::TestCase
15
15
  @user.friends = [@other_user]
16
16
  end
17
17
 
18
+ def test_has_permission
19
+ expect_http_posts_with_responses(has_app_permission_response_xml)
20
+ assert @user.has_permission?("status_update")
21
+ end
22
+
18
23
  def test_can_ask_user_if_he_or_she_is_friends_with_another_user
19
24
  assert(@user.friends_with?(@other_user))
20
25
  end
@@ -109,9 +114,13 @@ class UserTest < Test::Unit::TestCase
109
114
  @user.send_email("subject", nil, "body fbml")
110
115
  end
111
116
 
117
+ def test_doesnt_post_to_facebook_when_assigning_status
118
+ @session.expects(:post).never
119
+ @user.status="my status"
120
+ end
112
121
  def test_can_set_status_with_string
113
122
  @session.expects(:post).with('facebook.users.setStatus', :status=>"my status",:status_includes_verb=>1)
114
- @user.status="my status"
123
+ @user.set_status("my status")
115
124
  end
116
125
 
117
126
  def test_get_events
@@ -120,12 +129,18 @@ class UserTest < Test::Unit::TestCase
120
129
  events = @user.events
121
130
  assert_equal "29511517904", events.first.eid
122
131
  end
123
-
124
- def test_can_get_events
125
- @user.expects(:events)
126
- @user.events
132
+
133
+ def test_events_caching_honors_params
134
+ @user = Facebooker::User.new(9507801, @session)
135
+ @session.expects(:post).returns([{:eid=>1}])
136
+ assert_equal 1,@user.events.first.eid
137
+ @session.expects(:post).returns([{:eid=>2}])
138
+ assert_equal 2,@user.events(:start_time=>1.day.ago).first.eid
139
+ @session.expects(:post).never
140
+ assert_equal 1,@user.events.first.eid
127
141
  end
128
142
 
143
+
129
144
  def test_to_s
130
145
  assert_equal("1234",@user.to_s)
131
146
  end
@@ -226,4 +241,13 @@ class UserTest < Test::Unit::TestCase
226
241
  </connect_registerUsers_response>
227
242
  XML
228
243
  end
229
- end
244
+
245
+ def has_app_permission_response_xml
246
+ <<-XML
247
+ <?xml version="1.0" encoding="UTF-8"?>
248
+ <users_hasAppPermission_response xmlns="http://api.facebook.com/1.0/"
249
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
250
+ xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</users_hasAppPermission_response>
251
+ XML
252
+ end
253
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mmangino-facebooker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chad Fowler
@@ -115,6 +115,7 @@ files:
115
115
  - lib/facebooker/rails/facebook_pretty_errors.rb
116
116
  - lib/facebooker/rails/facebook_request_fix.rb
117
117
  - lib/facebooker/rails/facebook_session_handling.rb
118
+ - lib/facebooker/rails/facebook_url_helper.rb
118
119
  - lib/facebooker/rails/facebook_url_rewriting.rb
119
120
  - lib/facebooker/rails/helpers.rb
120
121
  - lib/facebooker/rails/profile_publisher_extensions.rb