rfacebook 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -36,6 +36,15 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36
36
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37
37
 
38
38
 
39
-
40
- Some code was inspired by techniques used in Alpha Chen's old client.
41
-
39
+ ============================== RELEASE NOTES ==============================
40
+
41
+ 0.9.8:
42
+ - split up the Gem (core library) and plugin (Rails extensions) - you will now have to update your Rails plugin separately from the Gem
43
+ - better documentation in the core library
44
+ - deprecated all the confusing is_valid/is_ready/is_activated/is_expired methods in favor of simply 'ready?' and 'expired?'
45
+ - removed the plugin code from the gem...the Rails plugin is now much better-separated
46
+ - moved unit tests that applied to the core into the Gem itself (rather than the plugin)
47
+ - cleaned out some unnecessary code in controller_extensions
48
+ - refactored signature checking so that it happens in the plugin rather than in the core lib
49
+ - added ssh_port to tunnel configuration (if for some reason you dont use 22)
50
+ - added 'log_out_of_facebook' method to force a user to log out (clears the fbsession data)
@@ -31,133 +31,94 @@ require "facebook_session"
31
31
 
32
32
  module RFacebook
33
33
 
34
- class FacebookDesktopSession < FacebookSession
34
+ class FacebookDesktopSession < FacebookSession
35
35
 
36
- ################################################################################################
37
- ################################################################################################
38
- # :section: Properties
39
- ################################################################################################
40
-
41
- attr_reader :session_secret # you should need this for infinite desktop sessions
42
-
43
- ################################################################################################
44
- ################################################################################################
45
- # :section: Initialization
46
- ################################################################################################
47
-
48
- # Function: initialize
49
- # Constructs a FacebookDesktopSession. Also calls the API to grab an auth_token.
50
- #
51
- # Parameters:
52
- # api_key - your API key
53
- # api_secret - your API secret
54
- # options.suppress_errors - boolean, set to true if you don't want errors to be thrown (defaults to false)
55
- def initialize(api_key, api_secret, suppress_errors = false)
56
- super(api_key, api_secret, suppress_errors)
57
- @desktop_auth_token = get_auth_token
58
- end
59
-
60
- ################################################################################################
61
- ################################################################################################
62
- # :section: URL Accessors
63
- ################################################################################################
64
-
65
- # Function: get_login_url
66
- # Gets the authentication URL
67
- #
68
- # Parameters:
69
- # options.next - the page to redirect to after login
70
- # options.popup - boolean, whether or not to use the popup style (defaults to true)
71
- # options.skipcookie - boolean, whether to force new Facebook login (defaults to false)
72
- # options.hidecheckbox - boolean, whether to show the "infinite session" option checkbox (defaults to false)
73
- def get_login_url(options={})
74
- # options
75
- path_next = options[:next] ||= nil
76
- popup = (options[:popup] == nil) ? true : false
77
- skipcookie = (options[:skipcookie] == nil) ? false : true
78
- hidecheckbox = (options[:hidecheckbox] == nil) ? false : true
36
+ # you should need this for infinite desktop sessions
37
+ attr_reader :session_secret
79
38
 
80
- # get some extra portions of the URL
81
- optionalNext = (path_next == nil) ? "" : "&next=#{CGI.escape(path_next.to_s)}"
82
- optionalPopup = (popup == true) ? "&popup=true" : ""
83
- optionalSkipCookie = (skipcookie == true) ? "&skipcookie=true" : ""
84
- optionalHideCheckbox = (hidecheckbox == true) ? "&hide_checkbox=true" : ""
39
+ # Constructs a FacebookDesktopSession, calling the API to grab an auth_token.
40
+ #
41
+ # api_key:: your API key
42
+ # api_secret:: your API secret
43
+ # quiet:: boolean, set to true if you don't want errors to be thrown (defaults to false)
44
+ def initialize(api_key, api_secret, quiet = false)
45
+ super(api_key, api_secret, quiet)
46
+ result = remote_call("auth.createToken", {})
47
+ @desktop_auth_token = result.at("auth_createToken_response")
48
+ @desktop_auth_token = @desktop_auth_token.nil? ? nil : @desktop_auth_token.inner_html.to_s
49
+ end
85
50
 
86
- # build and return URL
87
- return "http://#{WWW_SERVER_BASE_URL}#{WWW_PATH_LOGIN}?v=1.0&api_key=#{@api_key}&auth_token=#{@desktop_auth_token}#{optionalPopup}#{optionalNext}#{optionalSkipCookie}#{optionalHideCheckbox}"
88
- end
89
-
90
- ################################################################################################
91
- ################################################################################################
92
- # :section: Session Activation
93
- ################################################################################################
94
-
95
- # Function: activate
96
- # Use the internal auth_token to activate
97
- def activate
98
- result = call_method("auth.getSession", {:auth_token => @desktop_auth_token}, true)
99
- if result != nil
100
- @session_user_id = result.at("uid").inner_html
101
- @session_key = result.at("session_key").inner_html
102
- @session_secret = result.at("secret").inner_html
51
+ # Gets the authentication URL
52
+ #
53
+ # options.next:: the page to redirect to after login
54
+ # options.popup:: boolean, whether or not to use the popup style (defaults to true)
55
+ # options.skipcookie:: boolean, whether to force new Facebook login (defaults to false)
56
+ # options.hidecheckbox:: boolean, whether to show the "infinite session" option checkbox (defaults to false)
57
+ def get_login_url(options={})
58
+ # options
59
+ path_next = options[:next] ||= nil
60
+ popup = (options[:popup] == nil) ? true : false
61
+ skipcookie = (options[:skipcookie] == nil) ? false : true
62
+ hidecheckbox = (options[:hidecheckbox] == nil) ? false : true
63
+
64
+ # get some extra portions of the URL
65
+ optionalNext = (path_next == nil) ? "" : "&next=#{CGI.escape(path_next.to_s)}"
66
+ optionalPopup = (popup == true) ? "&popup=true" : ""
67
+ optionalSkipCookie = (skipcookie == true) ? "&skipcookie=true" : ""
68
+ optionalHideCheckbox = (hidecheckbox == true) ? "&hide_checkbox=true" : ""
69
+
70
+ # build and return URL
71
+ return "http://#{WWW_HOST}#{WWW_PATH_LOGIN}?v=1.0&api_key=#{@api_key}&auth_token=#{@desktop_auth_token}#{optionalPopup}#{optionalNext}#{optionalSkipCookie}#{optionalHideCheckbox}"
103
72
  end
104
- end
105
-
106
- # Function: activate_with_previous_session
107
- # Sets the session key and secret directly (for example, if you have an infinite session key)
108
- #
109
- # Parameters:
110
- # key - the session key to use
111
- # secret - the session secret to use
112
- def activate_with_previous_session(key, secret)
113
- # set the session key and secret
114
- @session_key = key
115
- @session_secret = secret
116
73
 
117
- # determine the current user's id
118
- result = call_method("users.getLoggedInUser")
119
- @session_user_id = result.at("users_getLoggedInUser_response").inner_html
120
- end
121
-
122
- protected
123
-
124
- # Function: auth_createToken
125
- # Returns a string auth_token
126
- def get_auth_token # :nodoc:
127
- result = call_method("auth.createToken", {})
128
- result = result.at("auth_createToken_response").inner_html.to_s ||= result.at("auth_createToken_response").inner_html.to_s
129
- return result
130
- end
131
-
74
+ # Activates the session and makes it ready for usage. Call this method only after
75
+ # the user has logged in via the login URL.
76
+ def activate
77
+ result = remote_call("auth.getSession", {:auth_token => @desktop_auth_token}, true)
78
+ if result != nil
79
+ @session_user_id = result.at("uid").inner_html
80
+ @session_key = result.at("session_key").inner_html
81
+ @session_secret = result.at("secret").inner_html
82
+ end
83
+ end
132
84
 
133
- ################################################################################################
134
- ################################################################################################
135
- # :section: Template Methods
136
- ################################################################################################
85
+ # Activate using the session key and secret directly (for example, if you have an infinite session)
86
+ #
87
+ # key:: the session key to use
88
+ # secret:: the session secret to use
89
+ def activate_with_previous_session(key, secret)
90
+ # set the session key and secret
91
+ @session_key = key
92
+ @session_secret = secret
137
93
 
138
- # Function: is_activated?
139
- # Returns true when we have activated ourselves somehow
140
- def is_activated?
141
- return (@session_key != nil and @session_secret != nil)
142
- end
94
+ # determine the current user's id
95
+ result = remote_call("users.getLoggedInUser")
96
+ @session_user_id = result.at("users_getLoggedInUser_response").inner_html
97
+ end
143
98
 
144
- # Function: get_secret
145
- # Used by super::signature to generate a signature.
146
- # Desktop sessions should use their session_secret rather than the api_secret
147
- # for any calls other than the call to createToken and getSession
148
- def get_secret(params) # :nodoc:
149
-
150
- if ( params[:method] != "facebook.auth.getSession" and params[:method] != "facebook.auth.createToken")
151
- return @session_secret
152
- else
153
- return @api_secret
99
+ # returns true if this session is completely ready to be used and make API calls
100
+ def ready?
101
+ return (@session_key != nil and @session_secret != nil and !expired?)
154
102
  end
103
+
104
+ # Used for signing a set of parameters in the way that Facebook
105
+ # specifies: <http://developers.facebook.com/documentation.php?v=1.0&doc=auth>
106
+ #
107
+ # params:: a Hash containing the parameters to sign
108
+ def signature(params)
109
+ # choose the proper secret
110
+ signatureSecret = nil
111
+ unless (params[:method] == "facebook.auth.getSession" or params[:method] == "facebook.auth.createToken")
112
+ signatureSecret = @session_secret
113
+ else
114
+ signatureSecret = @api_secret
115
+ end
155
116
 
156
- end
117
+ # sign the parameters with that secret
118
+ return signature_helper(params, signatureSecret)
119
+ end
157
120
 
158
- end
159
-
160
-
121
+ end
161
122
 
162
123
  end
163
124
 
@@ -27,10 +27,6 @@
27
27
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
  #
29
29
 
30
- #
31
- # Some code was inspired by techniques used in Alpha Chen's old client.
32
- #
33
-
34
30
  require "digest/md5"
35
31
  require "net/https"
36
32
  require "cgi"
@@ -38,389 +34,341 @@ require "facepricot"
38
34
 
39
35
  module RFacebook
40
36
 
41
- API_SERVER_BASE_URL = "api.facebook.com"
42
- API_PATH_REST = "/restserver.php"
37
+ # TODO: better handling of session expiration
38
+ # TODO: support Bebo's API
43
39
 
44
- WWW_SERVER_BASE_URL = "www.facebook.com"
45
- WWW_PATH_LOGIN = "/login.php"
46
- WWW_PATH_ADD = "/add.php"
47
- WWW_PATH_INSTALL = "/install.php"
40
+ API_VERSION = "1.0"
48
41
 
49
- class FacebookSession
42
+ API_HOST = "api.facebook.com"
43
+ API_PATH_REST = "/restserver.php"
44
+
45
+ WWW_HOST = "www.facebook.com"
46
+ WWW_PATH_LOGIN = "/login.php"
47
+ WWW_PATH_ADD = "/add.php"
48
+ WWW_PATH_INSTALL = "/install.php"
50
49
 
51
- ################################################################################################
52
- ################################################################################################
53
- # :section: Errors
54
- ################################################################################################
55
-
56
- class RemoteStandardError < StandardError; end
57
- class ExpiredSessionStandardError < StandardError; end
58
- class NotActivatedStandardError < StandardError; end
59
-
60
- ################################################################################################
61
- ################################################################################################
62
- # :section: Properties
63
- ################################################################################################
64
50
 
65
- # Property: session_user_id
66
- # The user id of the user associated with this sesssion.
67
- attr_reader :session_user_id
51
+ class FacebookSession
68
52
 
69
- # Property: session_key
70
- # The key for this session. You will need to save this for infinite sessions.
71
- attr_reader :session_key
53
+ ################################################################################################
54
+ ################################################################################################
55
+ # :section: Error classes
56
+ ################################################################################################
72
57
 
73
- # Property: session_expires
74
- # The expiration time of this session, as given from Facebook API login.
75
- attr_reader :session_expires
58
+ # TODO: better exception classes in v1.0?
59
+ class RemoteStandardError < StandardError
60
+ attr_reader :code
61
+ def initialize(message, code)
62
+ @code = code
63
+ end
64
+ end
65
+ class ExpiredSessionStandardError < RemoteStandardError; end
66
+ class NotActivatedStandardError < StandardError; end
67
+
68
+ ################################################################################################
69
+ ################################################################################################
70
+ # :section: Properties
71
+ ################################################################################################
76
72
 
77
- # Property: last_error_message
78
- # Contains a string message of the last error received from Facebook.
79
- attr_reader :last_error_message
73
+ # The user id of the user associated with this sesssion.
74
+ attr_reader :session_user_id
80
75
 
81
- # Property: last_error_code
82
- # Contains an integer code of the last error received from Facebook.
83
- attr_reader :last_error_code
76
+ # The key for this session. You will need to save this for infinite sessions.
77
+ attr_reader :session_key
84
78
 
85
- # Property: suppress_errors
86
- # By default, RFacebook will throw exceptions when errors occur.
87
- # You can set suppress_errors=true to stop these exceptions
88
- # from being thrown.
89
- attr_accessor :suppress_errors
79
+ # The expiration time of this session, as given from Facebook API login.
80
+ attr_reader :session_expires
90
81
 
91
- # Property: logger
92
- # Can be set to any valid logger (for example, RAIL_DEFAULT_LOGGER)
93
- attr_accessor :logger
82
+ # Can be set to any valid logger (for example, RAIL_DEFAULT_LOGGER)
83
+ attr_accessor :logger
94
84
 
95
- # Function: is_activated?
96
- # Returns true when the session has been activated in some way
97
- # THIS IS AN ABSTRACT METHOD (the value is determined differently for Web and Desktop sessions)
98
- def is_activated?
99
- raise StandardError
100
- end
85
+ ################################################################################################
86
+ ################################################################################################
87
+ # :section: Public Interface
88
+ ################################################################################################
89
+
90
+ # Constructs a FacebookSession.
91
+ #
92
+ # api_key:: your API key
93
+ # api_secret:: your API secret
94
+ # quiet:: boolean, set to true if you don't want exceptions to be thrown (defaults to false)
95
+ def initialize(api_key, api_secret, quiet = false)
96
+ # required parameters
97
+ @api_key = api_key
98
+ @api_secret = api_secret
99
+
100
+ # optional parameters
101
+ @quiet = quiet
102
+
103
+ # initialize internal state
104
+ @last_error_message = nil # DEPRECATED
105
+ @last_error_code = nil # DEPRECATED
106
+ @expired = false
107
+ end
101
108
 
102
- # Function: is_expired?
103
- # Returns true when the session has expired
104
- def is_expired?
105
- # TODO: this should look at the @session_expires as well
106
- return (@session_expired == true)
107
- end
109
+ # Template method. Returns true when the session is definitely prepared to make API calls.
110
+ def ready?
111
+ raise NotImplementedError
112
+ end
108
113
 
109
- # Function: is_valid?
110
- # Returns true when the session is definitely prepared to make API calls
111
- def is_valid?
112
- return (is_activated? and !is_expired?)
113
- end
114
+ # Returns true if the session is expired (will often mean that the session is not ready as well)
115
+ def expired?
116
+ return @expired
117
+ end
114
118
 
115
- # Function: is_ready?
116
- # alias for is_valid?
117
- def is_ready?
118
- return is_valid?
119
- end
119
+ # Returns true if exceptions are being suppressed in favor of log messages
120
+ def quiet?
121
+ return @quiet
122
+ end
120
123
 
121
- ################################################################################################
122
- ################################################################################################
123
- # :section: Initialization
124
- ################################################################################################
124
+ # Sets whether or not we suppress exceptions from being thrown
125
+ def quiet=(val)
126
+ @quiet = val
127
+ end
128
+
129
+ # Template method. Used for signing a set of parameters in the way that Facebook
130
+ # specifies: <http://developers.facebook.com/documentation.php?v=1.0&doc=auth>
131
+ #
132
+ # params:: a Hash containing the parameters to sign
133
+ def signature(params)
134
+ raise NotImplementedError
135
+ end
136
+
137
+ ################################################################################################
138
+ ################################################################################################
139
+ # :section: Utility methods
140
+ ################################################################################################
141
+ private
125
142
 
126
- # Function: initialize
127
- # Constructs a FacebookSession
128
- #
129
- # Parameters:
130
- # api_key - your API key
131
- # api_secret - your API secret
132
- # suppress_errors - boolean, set to true if you don't want exceptions to be thrown (defaults to false)
133
- #
134
- def initialize(api_key, api_secret, suppress_errors = false)
135
-
136
- # required parameters
137
- @api_key = api_key
138
- @api_secret = api_secret
139
-
140
- # optional parameters
141
- @suppress_errors = suppress_errors
142
-
143
- # initialize internal state
144
- @last_error_message = nil
145
- @last_error_code = nil
146
- @session_expired = false
143
+ # This allows *any* Facebook method to be called, using the Ruby
144
+ # mechanism for responding to unimplemented methods. Basically,
145
+ # this converts a call to "auth_getSession" to "auth.getSession"
146
+ # and does the proper API call using the parameter hash given.
147
+ #
148
+ # This allows you to call an API method such as facebook.users.getInfo
149
+ # by calling "fbsession.users_getInfo"
150
+ def method_missing(methodSymbol, *params)
151
+ # get the remote method name
152
+ remoteMethod = methodSymbol.to_s.gsub("_", ".")
153
+ if methodSymbol.to_s.match(/cached_(.*)/)
154
+ log_debug "** RFACEBOOK(GEM) - DEPRECATION NOTICE - cached methods are deprecated, making a raw call without caching."
155
+ tokens.shift
156
+ end
147
157
 
148
- # cache object for API calls
149
- @callcache = {}
150
-
151
- end
152
-
153
- ################################################################################################
154
- ################################################################################################
155
- # :section: API Calls
156
- ################################################################################################
157
- protected
158
+ # there can only be one parameter, a Hash, for remote methods
159
+ unless (params.size == 1 and params.first.is_a?(Hash))
160
+ log_debug "** RFACEBOOK(GEM) - when you call a remote Facebook method"
161
+ end
158
162
 
159
- # Function: method_missing
160
- # This allows *any* Facebook method to be called, using the Ruby
161
- # mechanism for responding to unimplemented methods. Basically,
162
- # this converts a call to "auth_getSession" to "auth.getSession"
163
- # and does the proper API call using the parameter hash given.
164
- #
165
- # This allows you to call an API method such as facebook.users.getInfo
166
- # by calling "fbsession.users_getInfo"
167
- #
168
- def method_missing(methodSymbol, *params)
169
- tokens = methodSymbol.to_s.split("_")
170
- if tokens[0] == "cached"
171
- tokens.shift
172
- return cached_call_method(tokens.join("."), params.first)
173
- else
174
- return call_method(tokens.join("."), params.first)
163
+ # make the remote method call
164
+ return remote_call(remoteMethod, params.first)
175
165
  end
176
- end
177
-
178
166
 
179
- # Function: call_method
180
- # Sets up the necessary parameters to make the POST request to the server
181
- #
182
- # Parameters:
183
- # method - i.e. "users.getInfo"
184
- # params - hash of key,value pairs for the parameters to this method
185
- # use_ssl - set to true if the call will be made over SSL
186
- def call_method(method, params={}, use_ssl=false) # :nodoc:
167
+ # Sets everything up to make a POST request to Facebook's API servers.
168
+ #
169
+ # method:: i.e. "users.getInfo"
170
+ # params:: hash of key,value pairs for the parameters to this method
171
+ # useSSL:: set to true if the call will be made over SSL
172
+ def remote_call(method, params={}, useSSL=false) # :nodoc:
187
173
 
188
- log_debug "** RFACEBOOK(GEM) - RFacebook::FacebookSession\#call_method - #{method}(#{params.inspect}) - making remote call"
189
-
190
- # ensure that this object has been activated somehow
191
- if (!method.include?("auth") and !is_activated?)
192
- raise NotActivatedStandardError, "You must activate the session before using it."
193
- end
194
-
195
- # set up params hash
196
- if (!params)
197
- params = {}
198
- end
199
- params = params.dup
174
+ log_debug "** RFACEBOOK(GEM) - RFacebook::FacebookSession\#remote_call - #{method}(#{params.inspect}) - making remote call"
200
175
 
201
- # params[:format] ||= @response_format
202
- params[:method] = "facebook.#{method}"
203
- params[:api_key] = @api_key
204
- params[:v] = "1.0"
176
+ # set up the parameters
177
+ params = (params || {}).dup
178
+ params[:method] = "facebook.#{method}"
179
+ params[:api_key] = @api_key
180
+ params[:v] = API_VERSION
181
+ # params[:format] ||= @response_format # TODO: consider JSON capability
205
182
 
206
- if (method != "auth.getSession" and method != "auth.createToken")
207
- params[:session_key] = session_key
208
- params[:call_id] = Time.now.to_f.to_s
209
- end
183
+ # non-auth methods get special consideration
184
+ unless(method == "auth.getSession" or method == "auth.createToken")
185
+ # session must be activated for non-auth methods
186
+ raise NotActivatedStandardError, "You must activate the session before using it." unless ready?
187
+
188
+ # secret and call ID must be set for non-auth methods
189
+ params[:session_key] = session_key
190
+ params[:call_id] = Time.now.to_f.to_s
191
+ end
210
192
 
211
- # convert arrays to comma-separated lists
212
- params.each{|k,v| params[k] = v.join(",") if v.is_a?(Array)}
193
+ # in the parameters, all arrays must be converted to comma-separated lists
194
+ params.each{|k,v| params[k] = v.join(",") if v.is_a?(Array)}
213
195
 
214
- # set up the param_signature value in the params
215
- params[:sig] = param_signature(params)
196
+ # sign the parameter list by adding a proper sig
197
+ params[:sig] = signature(params)
216
198
 
217
- # make the remote call and contain the results in a Facepricot XML object
218
- rawxml = post_request(params, use_ssl)
219
- xml = Facepricot.new(rawxml)
199
+ # make the remote call and contain the results in a Facepricot XML object
200
+ xml = post_request(params, useSSL)
201
+ return handle_xml_response(xml)
202
+ end
203
+
204
+ # Wraps an XML response in a Facepricot XML document, and checks for
205
+ # an error response (raising or logging errors as needed)
206
+ #
207
+ # NOTE: Facepricot chaining may be deprecated in the 1.0 release
208
+ def handle_xml_response(rawXML)
209
+ facepricotXML = Facepricot.new(rawXML)
220
210
 
221
- # error checking
222
- if xml.at("error_response")
211
+ # error checking
212
+ if facepricotXML.at("error_response")
223
213
 
224
- log_debug "** RFACEBOOK(GEM) - RFacebook::FacebookSession\#call_method - #{method}(#{params.inspect}) - remote call failed"
214
+ # get the error code
215
+ errorCode = facepricotXML.at("error_code").inner_html.to_i
216
+ errorMessage = facepricotXML.at("error_msg").inner_html
217
+ log_debug "** RFACEBOOK(GEM) - RFacebook::FacebookSession\#remote_call - remote call failed (#{errorCode}: #{errorMessage})"
225
218
 
226
- code = xml.at("error_code").inner_html.to_i
227
- msg = xml.at("error_msg").inner_html
228
- @last_error_message = "ERROR #{code}: #{msg} (#{method.inspect}, #{params.inspect})"
229
- @last_error_code = code
230
-
231
- # check to see if this error was an expired session error
232
- if code == 102
233
- @session_expired = true
234
- raise ExpiredSessionStandardError, @last_error_message unless @suppress_errors == true
235
- end
219
+ # TODO: remove these 2 lines
220
+ @last_error_message = "ERROR #{errorCode}: #{errorMessage}" # DEPRECATED
221
+ @last_error_code = errorCode # DEPRECATED
236
222
 
237
- # TODO: check for method not existing error (what code is it?)
238
- # and convert it to a Ruby "NoMethodError"
223
+ # check to see if this error was an expired session error
224
+ case errorCode
225
+
226
+ # the remote method did not exist, convert that to a standard Ruby no-method error
227
+ when 3
228
+ raise NoMethodError, errorMessage unless quiet? == true
229
+
230
+ # the parameters were wrong, or not enough parameters...convert that to a standard Ruby argument error
231
+ when 100,606
232
+ raise ArgumentError, errorMessage unless quiet? == true
233
+
234
+ # when the session expires, we need to record that internally
235
+ when 102
236
+ @expired = true
237
+ raise ExpiredSessionStandardError.new(errorMessage, errorCode) unless quiet? == true
239
238
 
240
- # otherwise, just throw a generic expired session
241
- raise RemoteStandardError, @last_error_message unless @suppress_errors == true
239
+ # otherwise, just raise a regular remote error with the error code
240
+ else
241
+ raise RemoteStandardError.new(errorMessage, errorCode) unless quiet? == true
242
+ end
242
243
 
243
- return nil
244
- end
244
+ # since the quiet flag may have been activated, we may not have thrown
245
+ # an actual exception, so we still need to return nil here
246
+ return nil
247
+ end
245
248
 
246
- return xml
247
- end
249
+ # everything was just fine, return the Facepricot XML response
250
+ return facepricotXML
251
+ end
248
252
 
249
- # Function: post_request
250
- # Posts a request to the remote Facebook API servers, and returns the
251
- # raw body of the result
252
- #
253
- # Parameters:
254
- # params - a Hash of the post parameters to send to the REST API
255
- # use_ssl - defaults to false, set to true if you want to use SSL for the POST
256
- def post_request(params, use_ssl=false)
257
-
258
- # get a server handle
259
- port = (use_ssl == true) ? 443 : 80
260
- http_server = Net::HTTP.new(API_SERVER_BASE_URL, port)
261
- http_server.use_ssl = use_ssl
253
+ # Posts a request to the remote Facebook API servers, and returns the
254
+ # raw text body of the result
255
+ #
256
+ # params:: a Hash of the post parameters to send to the REST API
257
+ # useSSL:: defaults to false, set to true if you want to use SSL for the POST
258
+ def post_request(params, useSSL=false)
259
+ # get a server handle
260
+ port = (useSSL == true) ? 443 : 80
261
+ http_server = Net::HTTP.new(API_HOST, port)
262
+ http_server.use_ssl = useSSL
262
263
 
263
- # build a request
264
- http_request = Net::HTTP::Post.new(API_PATH_REST)
265
- http_request.form_data = params
264
+ # build a request
265
+ http_request = Net::HTTP::Post.new(API_PATH_REST)
266
+ http_request.form_data = params
266
267
 
267
- # get the response XML
268
- return http_server.start{|http| http.request(http_request)}.body
269
- end
270
-
271
- # Function: cached_call_method
272
- # Does the same thing as call_method, except that the response is cached for
273
- # the lifetime of the FacebookSession.
274
- #
275
- # Parameters:
276
- # method - i.e. "users.getInfo"
277
- # params - hash of key,value pairs for the parameters to this method
278
- # use_ssl - set to true if the call will be made over SSL
279
- def cached_call_method(method,params={},use_ssl=false) # :nodoc:
280
- key = cache_key_for(method,params)
281
- log_debug "** RFACEBOOK(GEM) - RFacebook::FacebookSession\#cached_call_method - #{method}(#{params.inspect}) - attempting to hit cache"
282
- return @callcache[key] ||= call_method(method,params,use_ssl)
283
- end
268
+ # get the response XML
269
+ return http_server.start{|http| http.request(http_request)}.body
270
+ end
284
271
 
285
- # Function: cache_key_for
286
- # Key to use for cached method calls.
287
- #
288
- # Parameters:
289
- # method - the API method being cached
290
- # params - a Hash of the parameters being sent to the API
291
- #
292
- def cache_key_for(method,params) # :nodoc:
293
- pairs = []
294
- params.each do |k,v|
295
- if v.is_a?(Array)
296
- v = v.join(",")
297
- end
298
- pairs << "#{k}=#{v}"
272
+ # Generates a proper Facebook signature.
273
+ #
274
+ # params:: a Hash containing the parameters to sign
275
+ # secret:: the secret to use to sign the parameters
276
+ def signature_helper(params, secret) # :nodoc:
277
+ args = []
278
+ params.each{|k,v| args << "#{k}=#{v}"}
279
+ sortedArray = args.sort
280
+ requestStr = sortedArray.join("")
281
+ return Digest::MD5.hexdigest("#{requestStr}#{secret}")
299
282
  end
300
- return "#{method}(#{pairs.sort.join("...")})".to_sym
301
- end
302
283
 
303
- ################################################################################################
304
- ################################################################################################
305
- # :section: Signature Generation
306
- ################################################################################################
307
-
308
- # Function: get_secret
309
- # Returns the proper secret to sign a set of parameters with.
310
- # A WebSession will always use the api_secret, but a DesktopSession
311
- # sometimes needs to use a session_secret.
312
- #
313
- # THIS IS AN ABSTRACT METHOD
314
- #
315
- # Parameters:
316
- # params - a Hash containing the parameters to sign
317
- #
318
- def get_secret(params) # :nodoc:
319
- raise StandardError
320
- end
321
-
322
- # Function: param_signature
323
- # Generates a param_signature for a call to the API, per the spec on Facebook
324
- # see: <http://developers.facebook.com/documentation.php?v=1.0&doc=auth>
325
- #
326
- # Parameters:
327
- # params - a Hash containing the parameters to sign
328
- #
329
- def param_signature(params) # :nodoc:
330
- return generate_signature(params, get_secret(params));
331
- end
284
+ # log a debug message
285
+ def log_debug(message) # :nodoc:
286
+ @logger.debug(message) if @logger
287
+ end
332
288
 
333
- # Function: generate_signature
334
- # Generates a Facebook signature. Used for generating API calls, as well
335
- # as for checking the signature from a Canvas page
336
- #
337
- # Parameters:
338
- # hash - a Hash containing the parameters to sign
339
- # secret - the API or session secret to use to sign the parameters
340
- #
341
- def generate_signature(hash, secret) # :nodoc:
342
- args = []
343
- hash.each do |k,v|
344
- args << "#{k}=#{v}"
289
+ # log an informational message
290
+ def log_info(message) # :nodoc:
291
+ @logger.info(message) if @logger
345
292
  end
346
- sortedArray = args.sort
347
- requestStr = sortedArray.join("")
348
- return Digest::MD5.hexdigest("#{requestStr}#{secret}")
349
- end
350
293
 
351
- ################################################################################################
352
- ################################################################################################
353
- # :section: Marshalling Serialization Overrides
354
- ################################################################################################
355
- public
356
-
357
- def _dump(depth)
358
- instanceVarHash = {}
359
- self.instance_variables.each { |k| instanceVarHash[k] = self.instance_variable_get(k) }
360
- # the logger must be removed before serializing
361
- return Marshal.dump(instanceVarHash.delete_if{|k,v| k == "@logger"})
362
- end
294
+ ################################################################################################
295
+ ################################################################################################
296
+ # :section: Serialization
297
+ ################################################################################################
298
+ public
363
299
 
364
- def self._load(dumpedStr)
365
- instance = self.new(nil,nil)
366
- dumped = Marshal.load(dumpedStr)
367
- dumped.each do |k,v|
368
- instance.instance_variable_set(k,v)
300
+ # dump to a serialized string, removing the logger object (which cannot be serialized)
301
+ def _dump(depth) # :nodoc:
302
+ instanceVarHash = {}
303
+ self.instance_variables.each { |k| instanceVarHash[k] = self.instance_variable_get(k) }
304
+ return Marshal.dump(instanceVarHash.delete_if{|k,v| k == "@logger"})
369
305
  end
370
- return instance
371
- end
372
306
 
373
- ################################################################################################
374
- ################################################################################################
375
- # :section: Logging
376
- ################################################################################################
377
- private
307
+ # load from a serialized string
308
+ def self._load(dumpedStr) # :nodoc:
309
+ instance = self.new(nil,nil)
310
+ dumped = Marshal.load(dumpedStr)
311
+ dumped.each do |k,v|
312
+ instance.instance_variable_set(k,v)
313
+ end
314
+ return instance
315
+ end
378
316
 
379
- def log_debug(message) # :nodoc:
380
- @logger.debug(message) if @logger
381
- end
382
317
 
383
- def log_info(message) # :nodoc:
384
- @logger.info(message) if @logger
385
- end
318
+ ################################################################################################
319
+ ################################################################################################
320
+ # :section: Deprecated Methods
321
+ ################################################################################################
322
+ public
323
+
324
+ # DEPRECATED
325
+ def is_expired? # :nodoc:
326
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: is_expired? is deprecated, use expired? instead"
327
+ return expired?
328
+ end
329
+
330
+ # DEPRECATED
331
+ def is_activated? # :nodoc:
332
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: is_activated? is deprecated, use ready? instead"
333
+ return ready?
334
+ end
386
335
 
387
- ################################################################################################
388
- ################################################################################################
389
- # :section: Deprecated Methods
390
- ################################################################################################
391
- public
336
+ # DEPRECATED
337
+ def is_valid? # :nodoc:
338
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: is_valid? is deprecated, use ready? instead"
339
+ return ready?
340
+ end
392
341
 
393
- # DEPRECATED in favor of session_user_id
394
- def session_uid # :nodoc:
395
- log_debug "** RFACEBOOK(GEM) - DEPRECATION NOTICE - fbsession.session_uid is deprecated in favor of fbsession.session_user_id"
396
- return self.session_user_id
397
- end
342
+ # DEPRECATED
343
+ def is_ready? # :nodoc:
344
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: is_valid? is deprecated, use ready? instead"
345
+ return ready?
346
+ end
398
347
 
399
- # DEPRECATED in favor of last_error_message
400
- def last_error # :nodoc:
401
- log_debug "** RFACEBOOK(GEM) - DEPRECATION NOTICE - fbsession.last_error is deprecated in favor of fbsession.last_error_message"
402
- return self.last_error_message
403
- end
348
+ # DEPRECATED
349
+ def last_error_message # :nodoc:
350
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: last_error_message is deprecated"
351
+ return @last_error_message
352
+ end
404
353
 
405
- # DEPRECATED in favor of suppress_errors
406
- def suppress_exceptions # :nodoc:
407
- log_debug "** RFACEBOOK(GEM) - DEPRECATION NOTICE - fbsession.suppress_exceptions is deprecated in favor of fbsession.suppress_errors"
408
- return self.suppress_errors
409
- end
354
+ # DEPRECATED
355
+ def last_error_code # :nodoc:
356
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: last_error_code is deprecated"
357
+ return @last_error_code
358
+ end
410
359
 
411
- # DEPRECATED in favor of suppress_errors
412
- def suppress_exceptions=(value) # :nodoc:
413
- log_debug "** RFACEBOOK(GEM) - DEPRECATION NOTICE - fbsession.suppress_exceptions is deprecated in favor of fbsession.suppress_errors"
414
- self.suppress_errors = value
415
- end
360
+ # DEPRECATED
361
+ def suppress_errors # :nodoc:
362
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: suppress_errors is deprecated, use quiet? instead"
363
+ return quiet?
364
+ end
416
365
 
417
- # DEPRECATED in favor of is_expired?
418
- def session_expired?
419
- log_debug "** RFACEBOOK(GEM) - DEPRECATION NOTICE - fbsession.session_expired? is deprecated in favor of fbsession.is_expired?"
420
- return self.is_expired?
421
- end
422
-
366
+ # DEPRECATED
367
+ def suppress_errors=(val) # :nodoc:
368
+ RAILS_DEFAULT_LOGGER.info "** RFACEBOOK(GEM) DEPRECATION WARNING: suppress_errors= is deprecated, use quiet= instead"
369
+ @quiet=val
370
+ end
423
371
 
424
- end
372
+ end
425
373
 
426
374
  end