koala 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +8 -0
- data/Manifest +9 -5
- data/Rakefile +3 -3
- data/koala.gemspec +6 -6
- data/lib/graph_api.rb +126 -0
- data/lib/http_services.rb +8 -6
- data/lib/koala.rb +29 -124
- data/lib/rest_api.rb +28 -0
- data/readme.md +15 -7
- data/{test → spec}/facebook_data.yml +12 -10
- data/{test → spec}/koala/facebook_no_access_token_tests.rb +15 -44
- data/{test → spec}/koala/facebook_oauth_tests.rb +2 -13
- data/spec/koala/facebook_rest_api_no_access_token_test.rb +20 -0
- data/spec/koala/facebook_rest_api_with_access_token_test.rb +33 -0
- data/{test → spec}/koala/facebook_with_access_token_tests.rb +0 -0
- data/{test/koala_tests.rb → spec/koala_spec.rb} +7 -4
- metadata +16 -10
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
v0.6.0
|
2
|
+
-- Added support for the old REST API thanks to cbaclig's great work
|
3
|
+
-- Updated tests to conform to RSpec standards
|
4
|
+
-- Updated changelog, readme, etc.
|
5
|
+
|
6
|
+
v0.5.1
|
7
|
+
-- Documentation is now on the wiki, updated readme accordingly.
|
8
|
+
|
1
9
|
v0.5.0
|
2
10
|
-- Added several new OAuth methods for making and parsing access token requests
|
3
11
|
-- Added test suite for the OAuth class
|
data/Manifest
CHANGED
@@ -2,11 +2,15 @@ CHANGELOG
|
|
2
2
|
Manifest
|
3
3
|
Rakefile
|
4
4
|
init.rb
|
5
|
+
lib/graph_api.rb
|
5
6
|
lib/http_services.rb
|
6
7
|
lib/koala.rb
|
8
|
+
lib/rest_api.rb
|
7
9
|
readme.md
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
spec/facebook_data.yml
|
11
|
+
spec/koala/facebook_no_access_token_tests.rb
|
12
|
+
spec/koala/facebook_oauth_tests.rb
|
13
|
+
spec/koala/facebook_rest_api_no_access_token_test.rb
|
14
|
+
spec/koala/facebook_rest_api_with_access_token_test.rb
|
15
|
+
spec/koala/facebook_with_access_token_tests.rb
|
16
|
+
spec/koala_spec.rb
|
data/Rakefile
CHANGED
@@ -4,11 +4,11 @@ require 'rake'
|
|
4
4
|
require 'echoe'
|
5
5
|
|
6
6
|
# gem management
|
7
|
-
Echoe.new('koala', '0.
|
7
|
+
Echoe.new('koala', '0.6.0') do |p|
|
8
8
|
p.summary = "A lightweight, flexible library for Facebook's new Graph API"
|
9
|
-
p.description = "Koala is a lightweight, flexible Ruby SDK for Facebook's new Graph API. It allows read/write access to the Facebook Graph and provides OAuth URLs and cookie validation for Facebook Connect sites. Koala supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services."
|
9
|
+
p.description = "Koala is a lightweight, flexible Ruby SDK for Facebook's new Graph API. It allows read/write access to the Facebook Graph and provides OAuth URLs and cookie validation for Facebook Connect sites; it also supports access-token based interaction with the old REST API. Koala supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services."
|
10
10
|
p.url = "http://github.com/arsduo/koala"
|
11
|
-
p.author = ["Alex Koppel", "Rafi Jacoby", "Context Optional"]
|
11
|
+
p.author = ["Alex Koppel", "Chris Baclig", "Rafi Jacoby", "Context Optional"]
|
12
12
|
p.email = "alex@alexkoppel.com"
|
13
13
|
p.ignore_pattern = ["tmp/*", "script/*", "pkg/*"]
|
14
14
|
p.development_dependencies = []
|
data/koala.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{koala}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.6.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.authors = ["Alex Koppel, Rafi Jacoby, Context Optional"]
|
9
|
-
s.date = %q{2010-05-
|
10
|
-
s.description = %q{Koala is a lightweight, flexible Ruby SDK for Facebook's new Graph API. It allows read/write access to the Facebook Graph and provides OAuth URLs and cookie validation for Facebook Connect sites. Koala supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.}
|
8
|
+
s.authors = ["Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional"]
|
9
|
+
s.date = %q{2010-05-17}
|
10
|
+
s.description = %q{Koala is a lightweight, flexible Ruby SDK for Facebook's new Graph API. It allows read/write access to the Facebook Graph and provides OAuth URLs and cookie validation for Facebook Connect sites; it also supports access-token based interaction with the old REST API. Koala supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.}
|
11
11
|
s.email = %q{alex@alexkoppel.com}
|
12
|
-
s.extra_rdoc_files = ["CHANGELOG", "lib/http_services.rb", "lib/koala.rb"]
|
13
|
-
s.files = ["CHANGELOG", "Manifest", "Rakefile", "init.rb", "lib/http_services.rb", "lib/koala.rb", "readme.md", "
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/graph_api.rb", "lib/http_services.rb", "lib/koala.rb", "lib/rest_api.rb"]
|
13
|
+
s.files = ["CHANGELOG", "Manifest", "Rakefile", "init.rb", "lib/graph_api.rb", "lib/http_services.rb", "lib/koala.rb", "lib/rest_api.rb", "readme.md", "spec/facebook_data.yml", "spec/koala/facebook_no_access_token_tests.rb", "spec/koala/facebook_oauth_tests.rb", "spec/koala/facebook_rest_api_no_access_token_test.rb", "spec/koala/facebook_rest_api_with_access_token_test.rb", "spec/koala/facebook_with_access_token_tests.rb", "spec/koala_spec.rb", "koala.gemspec"]
|
14
14
|
s.homepage = %q{http://github.com/arsduo/koala}
|
15
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Koala", "--main", "readme.md"]
|
16
16
|
s.require_paths = ["lib"]
|
data/lib/graph_api.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module Koala
|
2
|
+
module Facebook
|
3
|
+
GRAPH_SERVER = "graph.facebook.com"
|
4
|
+
|
5
|
+
module GraphAPIMethods
|
6
|
+
# A client for the Facebook Graph API.
|
7
|
+
#
|
8
|
+
# See http://developers.facebook.com/docs/api for complete documentation
|
9
|
+
# for the API.
|
10
|
+
#
|
11
|
+
# The Graph API is made up of the objects in Facebook (e.g., people, pages,
|
12
|
+
# events, photos) and the connections between them (e.g., friends,
|
13
|
+
# photo tags, and event RSVPs). This client provides access to those
|
14
|
+
# primitive types in a generic way. For example, given an OAuth access
|
15
|
+
# token, this will fetch the profile of the active user and the list
|
16
|
+
# of the user's friends:
|
17
|
+
#
|
18
|
+
# graph = Koala::Facebook::GraphAPI.new(access_token)
|
19
|
+
# user = graph.get_object("me")
|
20
|
+
# friends = graph.get_connections(user["id"], "friends")
|
21
|
+
#
|
22
|
+
# You can see a list of all of the objects and connections supported
|
23
|
+
# by the API at http://developers.facebook.com/docs/reference/api/.
|
24
|
+
#
|
25
|
+
# You can obtain an access token via OAuth or by using the Facebook
|
26
|
+
# JavaScript SDK. See http://developers.facebook.com/docs/authentication/
|
27
|
+
# for details.
|
28
|
+
#
|
29
|
+
# If you are using the JavaScript SDK, you can use the
|
30
|
+
# Koala::Facebook::OAuth.get_user_from_cookie() method below to get the OAuth access token
|
31
|
+
# for the active user from the cookie saved by the SDK.
|
32
|
+
|
33
|
+
def get_object(id, args = {})
|
34
|
+
# Fetchs the given object from the graph.
|
35
|
+
api(id, args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_objects(ids, args = {})
|
39
|
+
# Fetchs all of the given object from the graph.
|
40
|
+
# We return a map from ID to object. If any of the IDs are invalid,
|
41
|
+
# we raise an exception.
|
42
|
+
api("", args.merge("ids" => ids.join(",")))
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_connections(id, connection_name, args = {})
|
46
|
+
# Fetchs the connections for given object.
|
47
|
+
api("#{id}/#{connection_name}", args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def put_object(parent_object, connection_name, args = {})
|
51
|
+
# Writes the given object to the graph, connected to the given parent.
|
52
|
+
#
|
53
|
+
# For example,
|
54
|
+
#
|
55
|
+
# graph.put_object("me", "feed", :message => "Hello, world")
|
56
|
+
#
|
57
|
+
# writes "Hello, world" to the active user's wall. Likewise, this
|
58
|
+
# will comment on a the first post of the active user's feed:
|
59
|
+
#
|
60
|
+
# feed = graph.get_connections("me", "feed")
|
61
|
+
# post = feed["data"][0]
|
62
|
+
# graph.put_object(post["id"], "comments", :message => "First!")
|
63
|
+
#
|
64
|
+
# See http://developers.facebook.com/docs/api#publishing for all of
|
65
|
+
# the supported writeable objects.
|
66
|
+
#
|
67
|
+
# Most write operations require extended permissions. For example,
|
68
|
+
# publishing wall posts requires the "publish_stream" permission. See
|
69
|
+
# http://developers.facebook.com/docs/authentication/ for details about
|
70
|
+
# extended permissions.
|
71
|
+
|
72
|
+
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
|
73
|
+
api("#{parent_object}/#{connection_name}", args, "post")
|
74
|
+
end
|
75
|
+
|
76
|
+
def put_wall_post(message, attachment = {}, profile_id = "me")
|
77
|
+
# Writes a wall post to the given profile's wall.
|
78
|
+
#
|
79
|
+
# We default to writing to the authenticated user's wall if no
|
80
|
+
# profile_id is specified.
|
81
|
+
#
|
82
|
+
# attachment adds a structured attachment to the status message being
|
83
|
+
# posted to the Wall. It should be a dictionary of the form:
|
84
|
+
#
|
85
|
+
# {"name": "Link name"
|
86
|
+
# "link": "http://www.example.com/",
|
87
|
+
# "caption": "{*actor*} posted a new review",
|
88
|
+
# "description": "This is a longer description of the attachment",
|
89
|
+
# "picture": "http://www.example.com/thumbnail.jpg"}
|
90
|
+
|
91
|
+
self.put_object(profile_id, "feed", attachment.merge({:message => message}))
|
92
|
+
end
|
93
|
+
|
94
|
+
def put_comment(object_id, message)
|
95
|
+
# Writes the given comment on the given post.
|
96
|
+
self.put_object(object_id, "comments", {:message => message})
|
97
|
+
end
|
98
|
+
|
99
|
+
def put_like(object_id)
|
100
|
+
# Likes the given post.
|
101
|
+
self.put_object(object_id, "likes")
|
102
|
+
end
|
103
|
+
|
104
|
+
def delete_object(id)
|
105
|
+
# Deletes the object with the given ID from the graph.
|
106
|
+
api(id, {}, "delete")
|
107
|
+
end
|
108
|
+
|
109
|
+
def search(search_terms, args = {})
|
110
|
+
# Searches for a given term
|
111
|
+
api("search", args.merge({:q => search_terms}))
|
112
|
+
end
|
113
|
+
|
114
|
+
def api(*args)
|
115
|
+
response = super
|
116
|
+
|
117
|
+
# check for errors
|
118
|
+
if response.is_a?(Hash) && error_details = response["error"]
|
119
|
+
raise APIError.new(error_details)
|
120
|
+
end
|
121
|
+
|
122
|
+
response
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/http_services.rb
CHANGED
@@ -6,14 +6,15 @@ module Koala
|
|
6
6
|
require 'net/http' unless defined?(Net::HTTP)
|
7
7
|
require 'net/https'
|
8
8
|
|
9
|
-
def self.make_request(path, args, verb)
|
9
|
+
def self.make_request(path, args, verb, options = {})
|
10
10
|
# We translate args to a valid query string. If post is specified,
|
11
11
|
# we send a POST request to the given path with the given arguments.
|
12
12
|
|
13
13
|
# if the verb isn't get or post, send it as a post argument
|
14
14
|
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
15
15
|
|
16
|
-
|
16
|
+
server = options[:rest_api] ? Facebook::REST_SERVER : Facebook::GRAPH_SERVER
|
17
|
+
http = Net::HTTP.new(server, 443)
|
17
18
|
http.use_ssl = true
|
18
19
|
# we turn off certificate validation to avoid the
|
19
20
|
# "warning: peer certificate won't be verified in this SSL session" warning
|
@@ -46,13 +47,14 @@ module Koala
|
|
46
47
|
base.class_eval do
|
47
48
|
require 'typhoeus' unless defined?(Typhoeus)
|
48
49
|
include Typhoeus
|
49
|
-
|
50
|
-
def self.make_request(path, args, verb)
|
50
|
+
|
51
|
+
def self.make_request(path, args, verb, options = {})
|
51
52
|
# if the verb isn't get or post, send it as a post argument
|
52
53
|
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
53
|
-
|
54
|
+
server = options[:rest_api] ? Facebook::REST_SERVER : Facebook::GRAPH_SERVER
|
55
|
+
self.send(verb, "https://#{server}/#{path}", :params => args).body
|
54
56
|
end
|
55
|
-
end
|
57
|
+
end # class_eval
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/lib/koala.rb
CHANGED
@@ -8,6 +8,12 @@ require 'json'
|
|
8
8
|
# include default http services
|
9
9
|
require 'http_services'
|
10
10
|
|
11
|
+
# add Graph API methods
|
12
|
+
require 'graph_api'
|
13
|
+
|
14
|
+
# add REST API methods
|
15
|
+
require 'rest_api'
|
16
|
+
|
11
17
|
module Koala
|
12
18
|
|
13
19
|
module Facebook
|
@@ -32,151 +38,50 @@ module Koala
|
|
32
38
|
# http://developers.facebook.com/docs/api. You can download the Facebook
|
33
39
|
# JavaScript SDK at http://github.com/facebook/connect-js/.
|
34
40
|
|
35
|
-
|
36
|
-
|
37
|
-
class GraphAPI
|
38
|
-
# A client for the Facebook Graph API.
|
39
|
-
#
|
40
|
-
# See http://developers.facebook.com/docs/api for complete documentation
|
41
|
-
# for the API.
|
42
|
-
#
|
43
|
-
# The Graph API is made up of the objects in Facebook (e.g., people, pages,
|
44
|
-
# events, photos) and the connections between them (e.g., friends,
|
45
|
-
# photo tags, and event RSVPs). This client provides access to those
|
46
|
-
# primitive types in a generic way. For example, given an OAuth access
|
47
|
-
# token, this will fetch the profile of the active user and the list
|
48
|
-
# of the user's friends:
|
49
|
-
#
|
50
|
-
# graph = Koala::Facebook::GraphAPI.new(access_token)
|
51
|
-
# user = graph.get_object("me")
|
52
|
-
# friends = graph.get_connections(user["id"], "friends")
|
53
|
-
#
|
54
|
-
# You can see a list of all of the objects and connections supported
|
55
|
-
# by the API at http://developers.facebook.com/docs/reference/api/.
|
56
|
-
#
|
57
|
-
# You can obtain an access token via OAuth or by using the Facebook
|
58
|
-
# JavaScript SDK. See http://developers.facebook.com/docs/authentication/
|
59
|
-
# for details.
|
60
|
-
#
|
61
|
-
# If you are using the JavaScript SDK, you can use the
|
62
|
-
# Koala::Facebook::OAuth.get_user_from_cookie() method below to get the OAuth access token
|
63
|
-
# for the active user from the cookie saved by the SDK.
|
64
|
-
|
41
|
+
class API
|
65
42
|
# initialize with an access token
|
66
43
|
def initialize(access_token = nil)
|
67
44
|
@access_token = access_token
|
68
45
|
end
|
69
|
-
|
70
|
-
def
|
71
|
-
# Fetchs the given object from the graph.
|
72
|
-
api(id, args)
|
73
|
-
end
|
74
|
-
|
75
|
-
def get_objects(ids, args = {})
|
76
|
-
# Fetchs all of the given object from the graph.
|
77
|
-
# We return a map from ID to object. If any of the IDs are invalid,
|
78
|
-
# we raise an exception.
|
79
|
-
api("", args.merge("ids" => ids.join(",")))
|
80
|
-
end
|
81
|
-
|
82
|
-
def get_connections(id, connection_name, args = {})
|
83
|
-
# Fetchs the connections for given object.
|
84
|
-
api("#{id}/#{connection_name}", args)
|
85
|
-
end
|
86
|
-
|
87
|
-
def put_object(parent_object, connection_name, args = {})
|
88
|
-
# Writes the given object to the graph, connected to the given parent.
|
89
|
-
#
|
90
|
-
# For example,
|
91
|
-
#
|
92
|
-
# graph.put_object("me", "feed", :message => "Hello, world")
|
93
|
-
#
|
94
|
-
# writes "Hello, world" to the active user's wall. Likewise, this
|
95
|
-
# will comment on a the first post of the active user's feed:
|
96
|
-
#
|
97
|
-
# feed = graph.get_connections("me", "feed")
|
98
|
-
# post = feed["data"][0]
|
99
|
-
# graph.put_object(post["id"], "comments", :message => "First!")
|
100
|
-
#
|
101
|
-
# See http://developers.facebook.com/docs/api#publishing for all of
|
102
|
-
# the supported writeable objects.
|
103
|
-
#
|
104
|
-
# Most write operations require extended permissions. For example,
|
105
|
-
# publishing wall posts requires the "publish_stream" permission. See
|
106
|
-
# http://developers.facebook.com/docs/authentication/ for details about
|
107
|
-
# extended permissions.
|
108
|
-
|
109
|
-
raise GraphAPIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
|
110
|
-
api("#{parent_object}/#{connection_name}", args, "post")
|
111
|
-
end
|
112
|
-
|
113
|
-
def put_wall_post(message, attachment = {}, profile_id = "me")
|
114
|
-
# Writes a wall post to the given profile's wall.
|
115
|
-
#
|
116
|
-
# We default to writing to the authenticated user's wall if no
|
117
|
-
# profile_id is specified.
|
118
|
-
#
|
119
|
-
# attachment adds a structured attachment to the status message being
|
120
|
-
# posted to the Wall. It should be a dictionary of the form:
|
121
|
-
#
|
122
|
-
# {"name": "Link name"
|
123
|
-
# "link": "http://www.example.com/",
|
124
|
-
# "caption": "{*actor*} posted a new review",
|
125
|
-
# "description": "This is a longer description of the attachment",
|
126
|
-
# "picture": "http://www.example.com/thumbnail.jpg"}
|
127
|
-
|
128
|
-
self.put_object(profile_id, "feed", attachment.merge({:message => message}))
|
129
|
-
end
|
130
|
-
|
131
|
-
def put_comment(object_id, message)
|
132
|
-
# Writes the given comment on the given post.
|
133
|
-
self.put_object(object_id, "comments", {:message => message})
|
134
|
-
end
|
135
|
-
|
136
|
-
def put_like(object_id)
|
137
|
-
# Likes the given post.
|
138
|
-
self.put_object(object_id, "likes")
|
139
|
-
end
|
140
|
-
|
141
|
-
def delete_object(id)
|
142
|
-
# Deletes the object with the given ID from the graph.
|
143
|
-
api(id, {}, "delete")
|
144
|
-
end
|
145
|
-
|
146
|
-
def search(search_terms, args = {})
|
147
|
-
# Searches for a given term
|
148
|
-
api("search", args.merge({:q => search_terms}))
|
149
|
-
end
|
150
|
-
|
151
|
-
def api(path, args = {}, verb = "get")
|
46
|
+
|
47
|
+
def api(path, args = {}, verb = "get", options = {})
|
152
48
|
# Fetches the given path in the Graph API.
|
153
49
|
args["access_token"] = @access_token if @access_token
|
154
50
|
|
155
51
|
# make the request via the provided service
|
156
|
-
result = Koala.make_request(path, args, verb)
|
52
|
+
result = Koala.make_request(path, args, verb, options)
|
157
53
|
|
158
54
|
# Facebook sometimes sends results like "true" and "false", which aren't strictly object
|
159
55
|
# and cause JSON.parse to fail
|
160
56
|
# so we account for that
|
161
57
|
response = JSON.parse("[#{result}]")[0]
|
162
58
|
|
163
|
-
# check for errors
|
164
|
-
if response.is_a?(Hash) && error_details = response["error"]
|
165
|
-
raise GraphAPIError.new(error_details)
|
166
|
-
end
|
167
|
-
|
168
59
|
response
|
169
60
|
end
|
170
61
|
end
|
171
|
-
|
172
|
-
class
|
62
|
+
|
63
|
+
class GraphAPI < API
|
64
|
+
include GraphAPIMethods
|
65
|
+
end
|
66
|
+
|
67
|
+
class RestAPI < API
|
68
|
+
include RestAPIMethods
|
69
|
+
end
|
70
|
+
|
71
|
+
class GraphAndRestAPI < API
|
72
|
+
include GraphAPIMethods
|
73
|
+
include RestAPIMethods
|
74
|
+
end
|
75
|
+
|
76
|
+
class APIError < Exception
|
173
77
|
attr_accessor :fb_error_type
|
174
78
|
def initialize(details = {})
|
175
79
|
self.fb_error_type = details["type"]
|
176
80
|
super("#{fb_error_type}: #{details["message"]}")
|
177
81
|
end
|
178
82
|
end
|
179
|
-
|
83
|
+
|
84
|
+
|
180
85
|
class OAuth
|
181
86
|
attr_accessor :app_id, :app_secret, :oauth_callback_url
|
182
87
|
def initialize(app_id, app_secret, oauth_callback_url = nil)
|
@@ -260,7 +165,7 @@ module Koala
|
|
260
165
|
result = fetch_token_string(code)
|
261
166
|
|
262
167
|
# if we have an error, parse the error JSON and raise an error
|
263
|
-
raise
|
168
|
+
raise APIError.new((JSON.parse(result)["error"] rescue nil) || {}) if result =~ /error/
|
264
169
|
# otherwise, parse the access token
|
265
170
|
parse_access_token(result)
|
266
171
|
end
|
@@ -280,4 +185,4 @@ module Koala
|
|
280
185
|
rescue LoadError
|
281
186
|
Koala.http_service = NetHTTPService
|
282
187
|
end
|
283
|
-
end
|
188
|
+
end
|
data/lib/rest_api.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Koala
|
2
|
+
module Facebook
|
3
|
+
REST_SERVER = "api.facebook.com"
|
4
|
+
|
5
|
+
module RestAPIMethods
|
6
|
+
def fql_query(fql)
|
7
|
+
args = {
|
8
|
+
"query" => fql,
|
9
|
+
"format" => "json",
|
10
|
+
}
|
11
|
+
|
12
|
+
api('method/fql.query', args, 'get', :rest_api => true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def api(*args)
|
16
|
+
response = super
|
17
|
+
|
18
|
+
# check for REST API-specific errors
|
19
|
+
if response.is_a?(Hash) && response["error_code"]
|
20
|
+
raise APIError.new("type" => response["error_code"], "message" => response["error_msg"])
|
21
|
+
end
|
22
|
+
|
23
|
+
response
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end # module Facebook
|
28
|
+
end # module Koala
|
data/readme.md
CHANGED
@@ -18,9 +18,19 @@ If you're using Koala within a web application with the Facebook
|
|
18
18
|
[JavaScript SDK](http://github.com/facebook/connect-js), you can use the Koala::Facebook::OAuth class
|
19
19
|
to parse the cookies set by the JavaScript SDK for logged in users.
|
20
20
|
|
21
|
+
FQL and the old-school REST API
|
22
|
+
-----
|
23
|
+
Where the Graph API and the old REST API overlap, you should choose the Graph API. Unfortunately, that overlap is far from complete, and there are many important API calls -- including fql.query -- that can't yet be done via the Graph.
|
24
|
+
|
25
|
+
Koala now supports the old-school REST API using OAuth access tokens; to use this, instantiate your class using the GraphAndRestAPI class:
|
26
|
+
|
27
|
+
api = Koala::Facebook::GraphAndRestAPI.new(oauth_access_token)
|
28
|
+
|
29
|
+
The GraphAndRestAPI class provides access to all the Graph API methods, as well as an fql method that you can use to make FQL calls. (You can pass the :rest\_api => true option to the api method to make REST API calls; check out lib/rest\_api.rb to see how it's done.) We reserve the right to expand the built-in REST API coverage to additional methods in the future, depending on how fast Facebook moves to fill in the gaps.
|
30
|
+
|
21
31
|
Examples and More Details
|
22
32
|
-----
|
23
|
-
|
33
|
+
Complete Koala documentation can now be found <a href="http://wiki.github.com/arsduo/koala/">on the wiki</a>!
|
24
34
|
|
25
35
|
You can easily generate OAuth access tokens and any other data needed to play with the Graph API or OAuth at the Koala-powered <a href="http://oauth.twoalex.com" target="_blank">OAuth Playground</a>.
|
26
36
|
|
@@ -28,17 +38,15 @@ You can easily generate OAuth access tokens and any other data needed to play wi
|
|
28
38
|
Testing
|
29
39
|
-----
|
30
40
|
|
31
|
-
Unit tests are provided for
|
41
|
+
Unit tests are provided for all of Koala's methods; however, because the OAuth access tokens and cookies expire, you have to provide some of your own data: a valid OAuth access token with publish_stream and read_stream permissions and an OAuth code that can be used to generate an access token. (The file also provides valid values for other tests, which you're welcome to sub out for data specific to your own application.)
|
42
|
+
|
43
|
+
Insert the required values into the file test/facebook_data.yml, then run the test as follows:
|
32
44
|
spec koala_tests.rb
|
33
45
|
|
34
|
-
Unit tests for cookie validation and other methods in the OAuth class will be provided shortly. (You'll also need to add that information into the yml.)
|
35
|
-
|
36
46
|
|
37
47
|
Coming Soon
|
38
48
|
-----
|
39
|
-
|
40
|
-
2. OAuth class method to directly fetch the access token when given a code value
|
41
|
-
|
49
|
+
* Support for real-time updates
|
42
50
|
|
43
51
|
Known Issues
|
44
52
|
-----
|
@@ -1,19 +1,17 @@
|
|
1
|
-
# Check out http://oauth.twoalex.com to easily generate tokens, cookies, etc.
|
1
|
+
# Check out http://oauth.twoalex.com/ to easily generate tokens, cookies, etc.
|
2
2
|
# Those values will work with the default settings in this yaml.
|
3
3
|
# Of course, you can change this to work with your own app.
|
4
4
|
# Just remember to update all fields!
|
5
|
-
|
6
|
-
#
|
7
|
-
# OAuth token should have publish_stream and read_stream permissions
|
8
|
-
oauth_token:
|
5
|
+
|
6
|
+
# You must supply this value yourself to test the GraphAPI class.
|
7
|
+
# Your OAuth token should have publish_stream and read_stream permissions.
|
8
|
+
oauth_token:
|
9
9
|
|
10
10
|
# for testing the OAuth class
|
11
11
|
# baseline app
|
12
|
-
oauth_test_data:
|
13
|
-
# You must supply
|
14
|
-
|
15
|
-
fbs_119908831367602: '"access_token=119908831367602|2.LKE7ksSPOx0V_8mHPr2NHQ__.3600.1273363200-2905623|CMpi0AYbn03Oukzv94AUha2qbO4.&expires=1273363200&secret=lT_9zm5r5IbJ6Aa5O54nFw__&session_key=2.LKE7ksSPOx0V_8mHPr2NHQ__.3600.1273363200-2905623&sig=9515e93113921f9476a4efbdd4a3c746&uid=2905623"'
|
16
|
-
code: 2.6GneoQbnEqtSiPppZzDU4Q__.3600.1273366800-2905623|vdiZmnxKxh4WVSnxBxoEvcBfamU.
|
12
|
+
oauth_test_data:
|
13
|
+
# You must supply this value yourself, since they will expire.
|
14
|
+
code:
|
17
15
|
|
18
16
|
# These values will work out of the box
|
19
17
|
app_id: 119908831367602
|
@@ -21,6 +19,10 @@ oauth_test_data:
|
|
21
19
|
callback_url: http://oauth.twoalex.com/
|
22
20
|
raw_token_string: "access_token=119908831367602|2.6GneoQbnEqtSiPppZzDU4Q__.3600.1273366800-2905623|3OLa3w0x1K4C1S5cOgbs07TytAk.&expires=6621"
|
23
21
|
raw_offline_access_token_string: access_token=119908831367602|2.6GneoQbnEqtSiPppZzDU4Q__.3600.1273366800-2905623|3OLa3w0x1K4C1S5cOgbs07TytAk.
|
22
|
+
valid_cookies:
|
23
|
+
# note: the tests stub the time class so these default cookies are always valid (if you're using the default app)
|
24
|
+
# if not you may want to remove the stubbing to test expiration
|
25
|
+
fbs_119908831367602: '"access_token=119908831367602|2.LKE7ksSPOx0V_8mHPr2NHQ__.3600.1273363200-2905623|CMpi0AYbn03Oukzv94AUha2qbO4.&expires=1273363200&secret=lT_9zm5r5IbJ6Aa5O54nFw__&session_key=2.LKE7ksSPOx0V_8mHPr2NHQ__.3600.1273363200-2905623&sig=9515e93113921f9476a4efbdd4a3c746&uid=2905623"'
|
24
26
|
expired_cookies:
|
25
27
|
fbs_119908831367602: '"access_token=119908831367602|2.xv9mi6QSOpr474s4n2X_pw__.3600.1273287600-2905623|yVt5WH_S6J5p3gFa5_5lBzckhws.&expires=1273287600&secret=V_E79ovQnXqxGctFuC_n5A__&session_key=2.xv9mi6QSOpr474s4n2X_pw__.3600.1273287600-2905623&sig=eeef60838c0c800258d89b7e6ddddddb&uid=2905623"'
|
26
28
|
offline_access_cookies:
|
@@ -25,12 +25,7 @@ class FacebookNoAccessTokenTests < Test::Unit::TestCase
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should not be able to get data about 'me'" do
|
28
|
-
|
29
|
-
@graph.get_object("me")
|
30
|
-
rescue Koala::Facebook::GraphAPIError => @right_err
|
31
|
-
rescue Exception => wrong_err
|
32
|
-
end
|
33
|
-
@right_err.should_not be_nil
|
28
|
+
lambda { @graph.get_object("me") }.should raise_error(Koala::Facebook::APIError)
|
34
29
|
end
|
35
30
|
|
36
31
|
it "should be able to get multiple objects" do
|
@@ -39,12 +34,7 @@ class FacebookNoAccessTokenTests < Test::Unit::TestCase
|
|
39
34
|
end
|
40
35
|
|
41
36
|
it "shouldn't be able to access connections from users" do
|
42
|
-
|
43
|
-
@graph.get_connections("lukeshepard", "likes")
|
44
|
-
rescue Koala::Facebook::GraphAPIError => @right_err
|
45
|
-
rescue Exception => wrong_err
|
46
|
-
end
|
47
|
-
@right_err.should_not be_nil
|
37
|
+
lambda { @graph.get_connections("lukeshepard", "likes") }.should raise_error(Koala::Facebook::APIError)
|
48
38
|
end
|
49
39
|
|
50
40
|
it "should be able to access connections from public Pages" do
|
@@ -53,53 +43,34 @@ class FacebookNoAccessTokenTests < Test::Unit::TestCase
|
|
53
43
|
end
|
54
44
|
|
55
45
|
it "should not be able to put an object" do
|
56
|
-
|
57
|
-
|
58
|
-
rescue Koala::Facebook::GraphAPIError => @right_err
|
59
|
-
rescue Exception => wrong_err
|
60
|
-
end
|
61
|
-
@right_err.should_not be_nil
|
46
|
+
lambda { @result = @graph.put_object("lukeshepard", "feed", :message => "Hello, world") }.should raise_error(Koala::Facebook::APIError)
|
47
|
+
puts "Error! Object #{@result.inspect} somehow put onto Luke Shepard's wall!" if @result
|
62
48
|
end
|
63
49
|
|
64
50
|
# these are not strictly necessary as the other put methods resolve to put_object, but are here for completeness
|
65
51
|
it "should not be able to post to a feed" do
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
@right_err.should_not be_nil
|
52
|
+
(lambda do
|
53
|
+
attachment = {:name => "Context Optional", :link => "http://www.contextoptional.com/"}
|
54
|
+
@result = @graph.put_wall_post("Hello, world", attachment, "contextoptional")
|
55
|
+
end).should raise_error(Koala::Facebook::APIError)
|
56
|
+
puts "Error! Object #{@result.inspect} somehow put onto Context Optional's wall!" if @result
|
72
57
|
end
|
73
58
|
|
74
59
|
it "should not be able to comment on an object" do
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
rescue Koala::Facebook::GraphAPIError => @right_err
|
79
|
-
rescue Exception => wrong_err
|
80
|
-
end
|
81
|
-
@right_err.should_not be_nil
|
60
|
+
# random public post on the ContextOptional wall
|
61
|
+
lambda { @result = @graph.put_comment("7204941866_119776748033392", "The hackathon was great!") }.should raise_error(Koala::Facebook::APIError)
|
62
|
+
puts "Error! Object #{@result.inspect} somehow commented on post 7204941866_119776748033392!" if @result
|
82
63
|
end
|
83
64
|
|
84
65
|
it "should not be able to like an object" do
|
85
|
-
|
86
|
-
@result = @graph.put_like("7204941866_119776748033392")
|
87
|
-
rescue Koala::Facebook::GraphAPIError => @right_err
|
88
|
-
rescue Exception => wrong_err
|
89
|
-
end
|
90
|
-
@right_err.should_not be_nil
|
66
|
+
lambda { @graph.put_like("7204941866_119776748033392") }.should raise_error(Koala::Facebook::APIError)
|
91
67
|
end
|
92
68
|
|
93
69
|
|
94
70
|
# DELETE
|
95
71
|
it "should not be able to delete posts" do
|
96
|
-
|
97
|
-
|
98
|
-
@result = @graph.delete_object("115349521819193_113815981982767")
|
99
|
-
rescue Koala::Facebook::GraphAPIError => @right_err
|
100
|
-
rescue Exception => wrong_err
|
101
|
-
end
|
102
|
-
@right_err.should_not be_nil
|
72
|
+
# test post on the Ruby SDK Test application
|
73
|
+
lambda { @result = @graph.delete_object("115349521819193_113815981982767") }.should raise_error(Koala::Facebook::APIError)
|
103
74
|
end
|
104
75
|
|
105
76
|
# SEARCH
|
@@ -123,13 +123,7 @@ class FacebookOAuthTests < Test::Unit::TestCase
|
|
123
123
|
|
124
124
|
it "should raise an exception if no callback is given in initialization or the call" do
|
125
125
|
oauth2 = Koala::Facebook::OAuth.new(@app_id, @secret)
|
126
|
-
|
127
|
-
url = oauth2.url_for_oauth_code
|
128
|
-
rescue ArgumentError => @right_err
|
129
|
-
rescue
|
130
|
-
end
|
131
|
-
|
132
|
-
@right_err.should
|
126
|
+
lambda { oauth2.url_for_oauth_code }.should raise_error(ArgumentError)
|
133
127
|
end
|
134
128
|
|
135
129
|
# url_for_access_token
|
@@ -190,12 +184,7 @@ class FacebookOAuthTests < Test::Unit::TestCase
|
|
190
184
|
end
|
191
185
|
|
192
186
|
it "should raise an error when get_access_token is called with a bad code" do
|
193
|
-
|
194
|
-
result = @oauth.get_access_token("foo")
|
195
|
-
rescue Koala::Facebook::GraphAPIError => @right_err
|
196
|
-
rescue
|
197
|
-
end
|
198
|
-
@right_err.should
|
187
|
+
lambda { @oauth.get_access_token("foo") }.should raise_error(Koala::Facebook::APIError)
|
199
188
|
end
|
200
189
|
end # describe
|
201
190
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class FacebookRestAPINoAccessTokenTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
describe "Koala RestAPI without an access token" do
|
4
|
+
before :each do
|
5
|
+
@graph = Koala::Facebook::RestAPI.new
|
6
|
+
end
|
7
|
+
|
8
|
+
# FQL
|
9
|
+
it "should be able to access public information via FQL" do
|
10
|
+
@result = @graph.fql_query('select first_name from user where uid = 216743')
|
11
|
+
@result.size.should == 1
|
12
|
+
@result.first['first_name'].should == 'Chris'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should not be able to access protected information via FQL" do
|
16
|
+
lambda { @graph.fql_query("select read_stream from permissions where uid = 216743") }.should raise_error(Koala::Facebook::APIError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class FacebookRestAPIWithAccessTokenTests < Test::Unit::TestCase
|
2
|
+
describe "Koala RestAPI with an access token" do
|
3
|
+
before :each do
|
4
|
+
@token = $testing_data["oauth_token"]
|
5
|
+
raise Exception, "Must supply access token to run FacebookRestAPIWithAccessTokenTests!" unless @token
|
6
|
+
@rest = Koala::Facebook::RestAPI.new(@token)
|
7
|
+
end
|
8
|
+
|
9
|
+
# FQL
|
10
|
+
it "should be able to access public information via FQL" do
|
11
|
+
result = @rest.fql_query('select first_name from user where uid = 216743')
|
12
|
+
result.size.should == 1
|
13
|
+
result.first['first_name'].should == 'Chris'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to access protected information via FQL" do
|
17
|
+
# Tests agains the permissions fql table
|
18
|
+
|
19
|
+
# get the current user's ID
|
20
|
+
# we're sneakily using the Graph API, which should be okay since it has its own tests
|
21
|
+
g = Koala::Facebook::GraphAPI.new(@token)
|
22
|
+
id = g.get_object("me", :fields => "id")["id"]
|
23
|
+
|
24
|
+
# now send a query about your permissions
|
25
|
+
result = @rest.fql_query("select read_stream from permissions where uid = #{id}")
|
26
|
+
|
27
|
+
result.size.should == 1
|
28
|
+
# we assume that you have read_stream permissions, so we can test against that
|
29
|
+
# (should we keep this?)
|
30
|
+
result.first["read_stream"].should == 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
File without changes
|
@@ -9,6 +9,8 @@ require 'koala'
|
|
9
9
|
require 'koala/facebook_no_access_token_tests'
|
10
10
|
require 'koala/facebook_with_access_token_tests'
|
11
11
|
require 'koala/facebook_oauth_tests'
|
12
|
+
require 'koala/facebook_rest_api_with_access_token_test'
|
13
|
+
require 'koala/facebook_rest_api_no_access_token_test'
|
12
14
|
|
13
15
|
class FacebookTestSuite
|
14
16
|
def self.suite
|
@@ -16,6 +18,8 @@ class FacebookTestSuite
|
|
16
18
|
suite << FacebookNoAccessTokenTests.suite
|
17
19
|
suite << FacebookWithAccessTokenTests.suite
|
18
20
|
suite << FacebookOAuthTests.suite
|
21
|
+
suite << FacebookRestAPIWithAccessTokenTests.suite
|
22
|
+
suite << FacebookRestAPINoAccessTokenTest.suite
|
19
23
|
suite
|
20
24
|
end
|
21
25
|
end
|
@@ -29,7 +33,6 @@ unless $testing_data["oauth_token"]
|
|
29
33
|
puts "Access token tests will fail until you store a valid token in facebook_data.yml"
|
30
34
|
end
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
# end
|
36
|
+
unless $testing_data["oauth_test_data"] && $testing_data["oauth_test_data"]["code"] && $testing_data["oauth_test_data"]["secret"]
|
37
|
+
puts "Cookie tests will fail until you store valid data for the cookie hash, app_id, and app secret in facebook_data.yml"
|
38
|
+
end
|
metadata
CHANGED
@@ -4,21 +4,21 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 6
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.6.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
|
-
- Alex Koppel, Rafi Jacoby, Context Optional
|
12
|
+
- Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-17 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
21
|
-
description: Koala is a lightweight, flexible Ruby SDK for Facebook's new Graph API. It allows read/write access to the Facebook Graph and provides OAuth URLs and cookie validation for Facebook Connect sites. Koala supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.
|
21
|
+
description: Koala is a lightweight, flexible Ruby SDK for Facebook's new Graph API. It allows read/write access to the Facebook Graph and provides OAuth URLs and cookie validation for Facebook Connect sites; it also supports access-token based interaction with the old REST API. Koala supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.
|
22
22
|
email: alex@alexkoppel.com
|
23
23
|
executables: []
|
24
24
|
|
@@ -26,21 +26,27 @@ extensions: []
|
|
26
26
|
|
27
27
|
extra_rdoc_files:
|
28
28
|
- CHANGELOG
|
29
|
+
- lib/graph_api.rb
|
29
30
|
- lib/http_services.rb
|
30
31
|
- lib/koala.rb
|
32
|
+
- lib/rest_api.rb
|
31
33
|
files:
|
32
34
|
- CHANGELOG
|
33
35
|
- Manifest
|
34
36
|
- Rakefile
|
35
37
|
- init.rb
|
38
|
+
- lib/graph_api.rb
|
36
39
|
- lib/http_services.rb
|
37
40
|
- lib/koala.rb
|
41
|
+
- lib/rest_api.rb
|
38
42
|
- readme.md
|
39
|
-
-
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
43
|
+
- spec/facebook_data.yml
|
44
|
+
- spec/koala/facebook_no_access_token_tests.rb
|
45
|
+
- spec/koala/facebook_oauth_tests.rb
|
46
|
+
- spec/koala/facebook_rest_api_no_access_token_test.rb
|
47
|
+
- spec/koala/facebook_rest_api_with_access_token_test.rb
|
48
|
+
- spec/koala/facebook_with_access_token_tests.rb
|
49
|
+
- spec/koala_spec.rb
|
44
50
|
- koala.gemspec
|
45
51
|
has_rdoc: true
|
46
52
|
homepage: http://github.com/arsduo/koala
|