lib/koala.rb in koala-0.7.2 vs lib/koala.rb in koala-0.7.3

- old
+ new

@@ -50,10 +50,15 @@ # Fetches the given path in the Graph API. args["access_token"] = @access_token || @app_access_token if @access_token || @app_access_token # make the request via the provided service result = Koala.make_request(path, args, verb, options) + # Check for any 500 errors before parsing the body + # since we're not guaranteed that the body is valid JSON + # in the case of a server error + raise APIError.new({"type" => "HTTP #{result.status.to_s}", "message" => "Response body: #{result.body}"}) if result.status >= 500 + # Parse the body as JSON and check for errors if provided a mechanism to do so # Note: Facebook sometimes sends results like "true" and "false", which aren't strictly objects # and cause JSON.parse to fail -- so we account for that by wrapping the result in [] body = response = JSON.parse("[#{result.body.to_s}]")[0] if error_checking_block @@ -101,15 +106,14 @@ @app_id = app_id @app_secret = app_secret @oauth_callback_url = oauth_callback_url end - def get_user_from_cookie(cookie_hash) + def get_user_info_from_cookie(cookie_hash) # Parses the cookie set by the official Facebook JavaScript SDK. # - # cookies should be a dictionary-like object mapping cookie names to - # cookie values. + # cookies should be a Hash, like the one Rails provides # # If the user is logged in via Facebook, we return a dictionary with the # keys "uid" and "access_token". The former is the user's Facebook ID, # and the latter can be used to make authenticated requests to the Graph API. # If the user is not logged in, we return None. @@ -130,12 +134,24 @@ auth_string = components.keys.sort.collect {|a| a == "sig" ? nil : "#{a}=#{components[a]}"}.reject {|a| a.nil?}.join("") sig = Digest::MD5.hexdigest(auth_string + @app_secret) sig == components["sig"] && (components["expires"] == "0" || Time.now.to_i < components["expires"].to_i) ? components : nil end end + alias_method :get_user_info_from_cookies, :get_user_info_from_cookie + + def get_user_from_cookie(cookies) + # overload this to be backward compatible with older implementations + # icky ruby magic, but it's _really_ cool we can do this + info = get_user_info_from_cookies(cookies) + string = info["uid"] + + overload_as_hash(string, info) + end alias_method :get_user_from_cookies, :get_user_from_cookie + # URLs + def url_for_oauth_code(options = {}) # for permissions, see http://developers.facebook.com/docs/authentication/permissions permissions = options[:permissions] scope = permissions ? "&scope=#{permissions.is_a?(Array) ? permissions.join(",") : permissions}" : "" @@ -155,22 +171,38 @@ callback = options[:callback] || @oauth_callback_url raise ArgumentError, "url_for_access_token must get a callback either from the OAuth object or in the parameters!" unless callback "https://#{GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{callback}&client_secret=#{@app_secret}&code=#{code}" end - def get_access_token(code) + def get_access_token_info(code) # convenience method to get a parsed token from Facebook for a given code # should this require an OAuth callback URL? get_token_from_server(:code => code, :redirect_uri => @oauth_callback_url) end - def get_app_access_token + def get_access_token(code) + info = get_access_token_info(code) + # upstream methods will throw errors if needed + string = info["access_token"] + + overload_as_hash(string, info) + end + + def get_app_access_token_info # convenience method to get a the application's sessionless access token get_token_from_server({:type => 'client_cred'}, true) end - def get_tokens_from_session_keys(sessions) + def get_app_access_token + info = get_app_access_token_info + string = info["access_token"] + + overload_as_hash(string, info) + end + + # from session keys + def get_token_info_from_session_keys(sessions) # fetch the OAuth tokens from Facebook response = fetch_token_string({ :type => 'client_cred', :sessions => sessions.join(",") }, true, "exchange_sessions") @@ -182,12 +214,25 @@ end JSON.parse(response) end + def get_tokens_from_session_keys(sessions) + # get the original hash results + results = get_token_info_from_session_keys(sessions) + # now recollect them as backward-compatible strings + # for easier use + results.collect do |r| + string = r["access_token"] + + overload_as_hash string, r + end + end + def get_token_from_session_key(session) # convenience method for a single key + # gets the overlaoded strings automatically get_tokens_from_session_keys([session])[0] end protected @@ -213,9 +258,26 @@ def fetch_token_string(args, post = false, endpoint = "access_token") Koala.make_request("oauth/#{endpoint}", { :client_id => @app_id, :client_secret => @app_secret }.merge!(args), post ? "post" : "get").body + end + + # overload the object to be accessible as a hash + # used to make get_*_token methods backward compatible + # icky ruby magic, but it's _really_ cool we can do this + def overload_as_hash(obj, hash) + command = <<-EOS + def [](index) + puts "WARNING: get_app_access_token now provides the access token as a string; use get_app_access_token_info if you want the hash with expirations. Otherwise you no longer need to call [] to get the token itself." + hash = #{hash.inspect} + hash[index] + end + EOS + + (class << obj; self; end).class_eval command + + obj end end end # finally, set up the http service Koala methods used to make requests