facebook_api 0.1.0
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/LICENSE +20 -0
- data/README.rdoc +62 -0
- data/lib/facebook_api/session.rb +112 -0
- data/lib/facebook_api.rb +117 -0
- metadata +127 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Tekin Suleyman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
= Facebook API
|
2
|
+
|
3
|
+
A simple, lightweight Ruby library for accessing the Facebook REST API. Currently used in Facebook Connect applications,
|
4
|
+
but could easily be extended for use in canvas applications.
|
5
|
+
|
6
|
+
== Usage
|
7
|
+
|
8
|
+
require 'facebook_api'
|
9
|
+
|
10
|
+
FacebookApi.configure do |config|
|
11
|
+
config.api_key = '55e9919b8c017abe484c9fb336dffb90'
|
12
|
+
config.secret_key 'fc881eb66493e0b845a3528c018cdd56'
|
13
|
+
config.canvas_page_name = 'crowdfm_publisher'
|
14
|
+
config.callback_url = 'http://crowd.fm/'
|
15
|
+
end
|
16
|
+
|
17
|
+
session = FacebookApi::Session.new(session_key, uid)
|
18
|
+
|
19
|
+
# Make REST API calls
|
20
|
+
response = session.call('Friends.get', :uid => '12345')
|
21
|
+
# Make calls with file attachments
|
22
|
+
response = session.call('Photos.upload', {:uid => '12345', :aid => '67890', :caption => 'your caption'}, File.new('/path/to/image.jpg))
|
23
|
+
# Make fql calls
|
24
|
+
response = session.call_fql('SELECT page_id FROM page_admin WHERE uid="12345"')
|
25
|
+
|
26
|
+
Both FacebookApi::Session#call and FacebookApi::Session#call_fql will generally return a hash, parsed from the JSON returned
|
27
|
+
by Facebook. However, for some API calls Facebook returns non-valid JSON, usually either 'true', 'false' or a string literal
|
28
|
+
(e.g. '12345'). In these cases, the return value from #call and #call_fql will be either true, false or the string literal
|
29
|
+
respectively.
|
30
|
+
|
31
|
+
=== How to use in a Rails application
|
32
|
+
|
33
|
+
With a couple of simple methods, you can make Facebook sessions available to you in your controllers and views:
|
34
|
+
|
35
|
+
class ApplicationController < ActionController::Base
|
36
|
+
# Requiring a valid facebook connect session for your controller actions with a before_filter:
|
37
|
+
before_filter :require_facebook_session, :except => [:login]
|
38
|
+
# Make the facebook_session available in your views by making it a helper_method:
|
39
|
+
helper_method :facebook_session
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def facebook_session
|
44
|
+
@facebook_session ||= facebook_session_from_cookies
|
45
|
+
end
|
46
|
+
|
47
|
+
def facebook_session_from_cookies
|
48
|
+
if FacebookApi.verify_connect_cookies_signature(cookies)
|
49
|
+
FacebookApi::Session.new(cookies["#{FacebookApi.api_key}_session_key"], cookies["#{FacebookApi.api_key}_user"])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def require_facebook_session
|
54
|
+
unless facebook_session
|
55
|
+
redirect_to facebook_connect_path
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
== Copyright
|
61
|
+
|
62
|
+
Copyright (c) 2010 Tekin Suleyman. See LICENSE for details.
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module FacebookApi
|
2
|
+
# FacebookApi::Session is your window to the Facebook REST API. Once you have a
|
3
|
+
# valid session, you can make API calls with #call and fql calls with #call_fql.
|
4
|
+
#
|
5
|
+
# Example usage:
|
6
|
+
#
|
7
|
+
# session = FacebookApi::Session.new(session_key, uid)
|
8
|
+
#
|
9
|
+
# # Make REST API calls
|
10
|
+
# response = session.call('Friends.get', :uid => '12345')
|
11
|
+
# # Make calls with file attachments
|
12
|
+
# response = session.call('Photos.upload', {:uid => '12345', :aid => '67890', :caption => 'your caption'}, File.new('/path/to/image.jpg))
|
13
|
+
# # Make fql calls
|
14
|
+
# response = session.call_fql('SELECT page_id FROM page_admin WHERE uid="12345"')
|
15
|
+
#
|
16
|
+
# The response from an API #call will usually be a hash, converted from the JSON
|
17
|
+
# returned by Facebook. For some API calls however, Facebook returns literal
|
18
|
+
# values such as 'true', 'false' or an identifier (e.g. '12334234').
|
19
|
+
# In these cases, #call returns either true, false or the literal respectively.
|
20
|
+
#
|
21
|
+
class Session
|
22
|
+
attr_reader :session_key, :uid #:nodoc:
|
23
|
+
|
24
|
+
# Initialise a FacebookApi::Session with a valid session key and uid.
|
25
|
+
def initialize(session_key, uid)
|
26
|
+
@session_key = session_key
|
27
|
+
@uid = uid
|
28
|
+
end
|
29
|
+
|
30
|
+
# Alias for the FacebookApi.logger.
|
31
|
+
def logger
|
32
|
+
FacebookApi.logger
|
33
|
+
end
|
34
|
+
|
35
|
+
# Makes a Facebook API REST call.
|
36
|
+
# If a file is specified, this will be included in the call, e.g. when calling Photos.upload.
|
37
|
+
# Example usage:
|
38
|
+
#
|
39
|
+
# response = session.call('Friends.get', :uid => '12345')
|
40
|
+
# response = session.call('Photos.upload', {:uid => '12345', :aid => '67890', :caption => 'your caption'}, File.new('/path/to/image.jpg))
|
41
|
+
#
|
42
|
+
# Returns the response from Facebook as either a hash, boolean or literal, depending on what Facebook returns.
|
43
|
+
# Raises FacebookApi::Error if Facebook returns with an error.
|
44
|
+
def call(method, params = {}, file = nil)
|
45
|
+
params[:method] = method
|
46
|
+
begin
|
47
|
+
params = prepare_params(params)
|
48
|
+
logger.debug "Sending request to facebook: #{params.inspect}"
|
49
|
+
params[nil] = file if file
|
50
|
+
response = RestClient.post(FacebookApi::REST_URL, params)
|
51
|
+
rescue SocketError => e
|
52
|
+
raise IOError.new("Cannot connect to facebook: #{e}")
|
53
|
+
end
|
54
|
+
logger.debug "Receiving response from facebook: \"#{response.body}\""
|
55
|
+
parse_facebook_json response
|
56
|
+
end
|
57
|
+
|
58
|
+
# Makes a Facebook API REST FQL call.
|
59
|
+
# Returns the response from Facebook as either a hash, boolean or literal, depending on what Facebook returns.
|
60
|
+
# Example:
|
61
|
+
#
|
62
|
+
# response = session.call('SELECT page_id FROM page_admin WHERE uid="12345"')
|
63
|
+
#
|
64
|
+
# Raises FacebookApi::Error if Facebook returns with an error.
|
65
|
+
def call_fql(query)
|
66
|
+
call('Fql.query', :query => query)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Prepares passed in params ready for sending to Facebook with a REST call.
|
70
|
+
def prepare_params(params)
|
71
|
+
s_params = {}
|
72
|
+
params.each_pair {|k,v| s_params[k.to_s] = v }
|
73
|
+
s_params['api_key'] = FacebookApi.api_key
|
74
|
+
s_params['v'] = FacebookApi::API_VERSION
|
75
|
+
s_params['call_id'] = Time.now.to_f.to_s
|
76
|
+
s_params['format'] = 'JSON'
|
77
|
+
s_params['sig'] = FacebookApi.calculate_signature(s_params)
|
78
|
+
s_params
|
79
|
+
end
|
80
|
+
|
81
|
+
# Because Facebook does not always return valid JSON, we need to pre-parse it and catch
|
82
|
+
# the special cases.
|
83
|
+
# If the response is valid JSON, this returns the parsed response. Otherwise it catches
|
84
|
+
# "true", "false" and string letirals, returning true, false or the string respectively.
|
85
|
+
# Raises Facebook::APIError if the response from Facebook is an error message.
|
86
|
+
def parse_facebook_json(response)
|
87
|
+
body = response.body
|
88
|
+
if looks_like_json? body
|
89
|
+
data = JSON.parse body
|
90
|
+
raise FacebookApi::Error.new(data['error_msg'], data['error_code']) if data.include?('error_msg')
|
91
|
+
else
|
92
|
+
data = parse_literal body
|
93
|
+
end
|
94
|
+
data
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def looks_like_json?(string)
|
100
|
+
# If it starts with a '[' or a '{', then it looks like JSON to me.
|
101
|
+
string =~ /^[\[\{]/
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_literal(string)
|
105
|
+
case string
|
106
|
+
when 'true' then true
|
107
|
+
when 'false' then false
|
108
|
+
else string
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/facebook_api.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'digest/sha2'
|
3
|
+
require 'rest_client'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'facebook_api/session'
|
7
|
+
|
8
|
+
module FacebookApi
|
9
|
+
|
10
|
+
class Configuration #:nodoc:
|
11
|
+
attr_accessor :api_key, :secret_key, :canvas_page_name, :callback_url
|
12
|
+
end
|
13
|
+
|
14
|
+
API_VERSION = '1.0' #:nodoc:
|
15
|
+
REST_URL = 'http://api.facebook.com/restserver.php' #:nodoc:
|
16
|
+
|
17
|
+
@logger = nil
|
18
|
+
@config = Configuration.new
|
19
|
+
|
20
|
+
# Returns the logger for Facebook calls.
|
21
|
+
# By default, this outputs to STDOUT.
|
22
|
+
def self.logger
|
23
|
+
unless @logger
|
24
|
+
@logger = ::Logger.new($stdout)
|
25
|
+
@logger.level = Logger::INFO
|
26
|
+
end
|
27
|
+
@logger
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the api key. set this with #configure.
|
31
|
+
def self.api_key
|
32
|
+
config.api_key
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the secret key. set this with #configure.
|
36
|
+
def self.secret_key
|
37
|
+
config.secret_key
|
38
|
+
end
|
39
|
+
|
40
|
+
# Allows you to set your Facebook configuration for accessing the REST API:
|
41
|
+
#
|
42
|
+
# FacebookApi.configure do |config|
|
43
|
+
# config.api_key = 'YOUR_API_KEY'
|
44
|
+
# config.secret_key = 'YOUR_SECRET_KEY'
|
45
|
+
# config.canvas_page_name = 'YOUR_CANVAS_PAGE_NAME'
|
46
|
+
# config.callback_url = 'YOUR_CALLBACK_URL'
|
47
|
+
# end
|
48
|
+
def self.configure(&block)
|
49
|
+
yield @config
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the current Facebook configuration. This gets set with #configure.
|
53
|
+
def self.config
|
54
|
+
@config
|
55
|
+
end
|
56
|
+
|
57
|
+
# Verifies the signature of parmaters sent by Facebook.
|
58
|
+
# Returns true if the signature is valid, false otherwise
|
59
|
+
# See the API docs here[http://wiki.developers.facebook.com/index.php/Verifying_The_Signature] for
|
60
|
+
# more details on how this is calculated.
|
61
|
+
def self.verify_facebook_params_signature(args)
|
62
|
+
signature = args.delete('fb_sig')
|
63
|
+
return false if signature.nil?
|
64
|
+
|
65
|
+
signed_args = Hash.new
|
66
|
+
args.each do |k, v|
|
67
|
+
if k =~ /^fb_sig_(.*)/
|
68
|
+
signed_args[$1] = v
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
signature == calculate_signature(signed_args)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Verifies the signature in the cookies set by Facebook Connect checks out.
|
76
|
+
# Returns true if the signature is valid, false otherwise.
|
77
|
+
# See the API docs here[http://wiki.developers.facebook.com/index.php/Verifying_The_Signature#Signatures_and_Facebook_Connect_Sites] for
|
78
|
+
# more details on how this is calculated.
|
79
|
+
def self.verify_connect_cookies_signature(args)
|
80
|
+
signature = args.delete(api_key)
|
81
|
+
return false if signature.nil?
|
82
|
+
|
83
|
+
signed_args = Hash.new
|
84
|
+
args.each do |k, v|
|
85
|
+
if k =~ /^#{api_key}_(.*)/
|
86
|
+
signed_args[$1] = v
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
signature == calculate_signature(signed_args)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Calculates a signature, as described in the API docs here[http://wiki.developers.facebook.com/index.php/Verifying_The_Signature#Generating_the_Signature].
|
94
|
+
def self.calculate_signature(params)
|
95
|
+
params_string = params.sort.inject('') { |str, pair| str << pair[0] << '=' << pair[1] }
|
96
|
+
Digest::MD5.hexdigest(params_string + secret_key)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Helper to convert <tt>ActiveSupport::TimeWithZone</tt> from local time to Pacific time.
|
100
|
+
# Use this when sending date/times to Facebook as Facebook expects times to be
|
101
|
+
# sent as Pacific time converted to a Unix timestamp.
|
102
|
+
def self.convert_time(time)
|
103
|
+
if time.is_a?(ActiveSupport::TimeWithZone)
|
104
|
+
pacific_zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
|
105
|
+
pacific_zone.parse(time.strftime("%Y-%m-%d %H:%M:%S"))
|
106
|
+
else
|
107
|
+
time
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Raised if a Facebook API call fails and returns an error response.
|
112
|
+
class Error < StandardError
|
113
|
+
def initialize(error_msg, error_code = 1) #:nodoc:
|
114
|
+
super("FacebookApi::Error #{error_code}: #{error_msg}" )
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: facebook_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Tekin Suleyman
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-07 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rest-client
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 4
|
30
|
+
- 2
|
31
|
+
version: 1.4.2
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: test-unit
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: shoulda
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
type: :development
|
57
|
+
version_requirements: *id003
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: mocha
|
60
|
+
prerelease: false
|
61
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id004
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: webmock
|
72
|
+
prerelease: false
|
73
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id005
|
82
|
+
description:
|
83
|
+
email: tekin@tekin.co.uk
|
84
|
+
executables: []
|
85
|
+
|
86
|
+
extensions: []
|
87
|
+
|
88
|
+
extra_rdoc_files:
|
89
|
+
- README.rdoc
|
90
|
+
files:
|
91
|
+
- LICENSE
|
92
|
+
- README.rdoc
|
93
|
+
- lib/facebook_api/session.rb
|
94
|
+
- lib/facebook_api.rb
|
95
|
+
has_rdoc: true
|
96
|
+
homepage: http://tekin.co.uk
|
97
|
+
licenses: []
|
98
|
+
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options:
|
101
|
+
- --main
|
102
|
+
- README.rdoc
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
version: "0"
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
segments:
|
117
|
+
- 0
|
118
|
+
version: "0"
|
119
|
+
requirements: []
|
120
|
+
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 1.3.6
|
123
|
+
signing_key:
|
124
|
+
specification_version: 3
|
125
|
+
summary: A simple, lightweight Ruby library for accessing the Facebook API
|
126
|
+
test_files: []
|
127
|
+
|