mmangino-facebooker 1.0.2 → 1.0.3

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.
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