koala 1.1.0 → 1.2.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/.travis.yml +2 -1
- data/CHANGELOG +36 -0
- data/Gemfile +6 -2
- data/Rakefile +0 -1
- data/koala.gemspec +7 -8
- data/lib/koala/batch_operation.rb +15 -15
- data/lib/koala/graph_api.rb +85 -73
- data/lib/koala/graph_batch_api.rb +21 -11
- data/lib/koala/graph_collection.rb +13 -8
- data/lib/koala/http_service.rb +176 -0
- data/lib/koala/oauth.rb +34 -24
- data/lib/koala/realtime_updates.rb +21 -18
- data/lib/koala/rest_api.rb +1 -1
- data/lib/koala/test_users.rb +33 -17
- data/lib/koala/uploadable_io.rb +49 -43
- data/lib/koala/utils.rb +11 -0
- data/lib/koala/version.rb +3 -0
- data/lib/koala.rb +47 -45
- data/readme.md +58 -38
- data/spec/cases/{api_base_spec.rb → api_spec.rb} +27 -2
- data/spec/cases/error_spec.rb +32 -0
- data/spec/cases/graph_and_rest_api_spec.rb +12 -21
- data/spec/cases/graph_api_batch_spec.rb +92 -119
- data/spec/cases/graph_api_spec.rb +11 -14
- data/spec/cases/graph_collection_spec.rb +116 -0
- data/spec/cases/http_service_spec.rb +446 -0
- data/spec/cases/koala_spec.rb +36 -37
- data/spec/cases/oauth_spec.rb +318 -212
- data/spec/cases/realtime_updates_spec.rb +45 -31
- data/spec/cases/rest_api_spec.rb +23 -7
- data/spec/cases/test_users_spec.rb +123 -75
- data/spec/cases/uploadable_io_spec.rb +77 -36
- data/spec/cases/utils_spec.rb +10 -0
- data/spec/fixtures/facebook_data.yml +26 -24
- data/spec/fixtures/mock_facebook_responses.yml +131 -101
- data/spec/spec_helper.rb +29 -5
- data/spec/support/graph_api_shared_examples.rb +80 -120
- data/spec/support/json_testing_fix.rb +35 -11
- data/spec/support/koala_test.rb +187 -0
- data/spec/support/mock_http_service.rb +8 -5
- data/spec/support/ordered_hash.rb +205 -0
- data/spec/support/rest_api_shared_examples.rb +37 -37
- data/spec/support/uploadable_io_shared_examples.rb +2 -8
- metadata +72 -83
- data/lib/koala/http_services/net_http_service.rb +0 -92
- data/lib/koala/http_services/typhoeus_service.rb +0 -37
- data/lib/koala/http_services.rb +0 -46
- data/spec/cases/http_services/http_service_spec.rb +0 -129
- data/spec/cases/http_services/net_http_service_spec.rb +0 -532
- data/spec/cases/http_services/typhoeus_service_spec.rb +0 -152
- data/spec/support/live_testing_data_helper.rb +0 -40
- data/spec/support/setup_mocks_or_live.rb +0 -51
data/.travis.yml
CHANGED
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
v1.2
|
|
2
|
+
New methods:
|
|
3
|
+
-- API is now the main API class, contains both Graph and REST methods
|
|
4
|
+
-- Old classes are aliased with deprecation warnings (non-breaking change)
|
|
5
|
+
-- TestUsers#update lets you update the name or password of an existing test user
|
|
6
|
+
-- API.get_page_access_token lets you easily fetch the access token for a page you manage (thanks, marcgg!)
|
|
7
|
+
-- Added version.rb (Koala::VERSION)
|
|
8
|
+
Updated methods:
|
|
9
|
+
-- OAuth now parses Facebook's new signed cookie format
|
|
10
|
+
-- API.put_picture now accepts URLs to images (thanks, marcgg!)
|
|
11
|
+
-- Bug fixes to put_picture, parse_signed_request, and the test suite (thanks, johnbhall and Will S.!)
|
|
12
|
+
-- Smarter GraphCollection use
|
|
13
|
+
-- Any pageable result will now become a GraphCollection
|
|
14
|
+
-- Non-pageable results from get_connections no longer error
|
|
15
|
+
-- GraphCollection.raw_results allows access to original result data
|
|
16
|
+
-- Koala no longer enforces any limits on the number of test users you create at once
|
|
17
|
+
Internal improvements:
|
|
18
|
+
-- Koala now uses Faraday to make requests, replacing the HTTPServices (see wiki)
|
|
19
|
+
-- Koala::HTTPService.http_options allows specification of default Faraday connection options
|
|
20
|
+
-- Koala::HTTPService.faraday_middleware allows custom middleware configurations
|
|
21
|
+
-- Koala now defaults to Net::HTTP rather than Typhoeus
|
|
22
|
+
-- Koala::NetHTTPService and Koala::TyphoeusService modules no longer exist
|
|
23
|
+
-- Koala no longer automatically switches to Net::HTTP when uploading IO objects to Facebook
|
|
24
|
+
-- RealTimeUpdates and TestUsers are no longer subclasses of API, but have their own .api objects
|
|
25
|
+
-- The old .graph_api accessor is aliases to .api with a deprecation warning
|
|
26
|
+
-- Removed deprecation warnings for pre-1.1 batch interface
|
|
27
|
+
Testing improvements:
|
|
28
|
+
-- Live test suites now run against test users by default
|
|
29
|
+
-- Test suite can be repeatedly run live without having to update facebook_data.yml
|
|
30
|
+
-- OAuth code and session key tests cannot be run against test users
|
|
31
|
+
-- Faraday adapter for live tests can be specified with ADAPTER=[your adapter] in the rspec command
|
|
32
|
+
-- Live tests can be run against the beta server by specifying BETA=true in the rspec command
|
|
33
|
+
-- Tests now pass against all rubies on Travis CI
|
|
34
|
+
-- Expanded and refactored test coverage
|
|
35
|
+
-- Fixed bug with YAML parsing in Ruby 1.9
|
|
36
|
+
|
|
1
37
|
v1.1
|
|
2
38
|
New methods:
|
|
3
39
|
-- Added Batch API support (thanks, seejohnrun and spiegela!)
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/koala.gemspec
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
|
3
|
+
require 'koala/version'
|
|
2
4
|
|
|
3
5
|
Gem::Specification.new do |s|
|
|
4
6
|
s.name = %q{koala}
|
|
5
|
-
s.version =
|
|
6
|
-
s.date = %q{2011-
|
|
7
|
+
s.version = Koala::VERSION
|
|
8
|
+
s.date = %q{2011-09-27}
|
|
7
9
|
|
|
8
10
|
s.summary = %q{A lightweight, flexible library for Facebook with support for the Graph API, the REST API, realtime updates, and OAuth authentication.}
|
|
9
11
|
s.description = %q{Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph and REST APIs, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.}
|
|
@@ -29,22 +31,19 @@ Gem::Specification.new do |s|
|
|
|
29
31
|
|
|
30
32
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
31
33
|
s.add_runtime_dependency(%q<multi_json>, ["~> 1.0"])
|
|
32
|
-
s.add_runtime_dependency(%q<
|
|
34
|
+
s.add_runtime_dependency(%q<faraday>, ["~> 0.7.0"])
|
|
33
35
|
s.add_development_dependency(%q<rspec>, ["~> 2.5"])
|
|
34
36
|
s.add_development_dependency(%q<rake>, ["~> 0.8.7"])
|
|
35
|
-
s.add_development_dependency(%q<typhoeus>, ["~> 0.2.4"])
|
|
36
37
|
else
|
|
37
38
|
s.add_dependency(%q<multi_json>, ["~> 1.0"])
|
|
38
|
-
s.add_dependency(%q<multipart-post>, ["~> 1.0"])
|
|
39
39
|
s.add_dependency(%q<rspec>, ["~> 2.5"])
|
|
40
40
|
s.add_dependency(%q<rake>, ["~> 0.8.7"])
|
|
41
|
-
s.add_dependency(%q<
|
|
41
|
+
s.add_dependency(%q<faraday>, ["~> 0.7.0"])
|
|
42
42
|
end
|
|
43
43
|
else
|
|
44
44
|
s.add_dependency(%q<multi_json>, ["~> 1.0"])
|
|
45
|
-
s.add_dependency(%q<multipart-post>, ["~> 1.0"])
|
|
46
45
|
s.add_dependency(%q<rspec>, ["~> 2.5"])
|
|
47
46
|
s.add_dependency(%q<rake>, ["~> 0.8.7"])
|
|
48
|
-
s.add_dependency(%q<
|
|
47
|
+
s.add_dependency(%q<faraday>, ["~> 0.7.0"])
|
|
49
48
|
end
|
|
50
49
|
end
|
|
@@ -18,25 +18,25 @@ module Koala
|
|
|
18
18
|
@url = options[:url]
|
|
19
19
|
@method = options[:method].to_sym
|
|
20
20
|
@post_processing = options[:post_processing]
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
process_binary_args
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
raise Koala::KoalaError, "Batch operations require an access token, none provided." unless @access_token
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
def to_batch_params(main_access_token)
|
|
28
28
|
# set up the arguments
|
|
29
29
|
args_string = Koala.http_service.encode_params(@access_token == main_access_token ? @args : @args.merge(:access_token => @access_token))
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
response = {
|
|
32
|
-
:method => @method.to_s,
|
|
32
|
+
:method => @method.to_s,
|
|
33
33
|
:relative_url => @url,
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
# handle batch-level arguments, such as name, depends_on, and attached_files
|
|
37
37
|
@batch_args[:attached_files] = @files.keys.join(",") if @files
|
|
38
38
|
response.merge!(@batch_args) if @batch_args
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
# for get and delete, we append args to the URL string
|
|
41
41
|
# otherwise, they go in the body
|
|
42
42
|
if args_string.length > 0
|
|
@@ -46,15 +46,15 @@ module Koala
|
|
|
46
46
|
response[:body] = args_string if args_string.length > 0
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
response
|
|
51
51
|
end
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
protected
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
def process_binary_args
|
|
56
56
|
# collect binary files
|
|
57
|
-
@args.each_pair do |key, value|
|
|
57
|
+
@args.each_pair do |key, value|
|
|
58
58
|
if UploadableIO.binary_content?(value)
|
|
59
59
|
@files ||= {}
|
|
60
60
|
# we use a class-level counter to ensure unique file identifiers across multiple batch operations
|
|
@@ -63,12 +63,12 @@ module Koala
|
|
|
63
63
|
id = "op#{identifier}_file#{@files.keys.length}"
|
|
64
64
|
@files[id] = @args.delete(key).is_a?(UploadableIO) ? value : UploadableIO.new(value)
|
|
65
65
|
end
|
|
66
|
-
end
|
|
66
|
+
end
|
|
67
67
|
end
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
def args_in_url?
|
|
70
|
-
@method == :get || @method == :delete
|
|
71
|
-
end
|
|
70
|
+
@method == :get || @method == :delete
|
|
71
|
+
end
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
end
|
data/lib/koala/graph_api.rb
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
module Koala
|
|
2
2
|
module Facebook
|
|
3
|
-
GRAPH_SERVER = "graph.facebook.com"
|
|
3
|
+
GRAPH_SERVER = "graph.facebook.com"
|
|
4
4
|
|
|
5
5
|
module GraphAPIMethods
|
|
6
6
|
# A client for the Facebook Graph API.
|
|
7
|
-
#
|
|
7
|
+
#
|
|
8
8
|
# See http://github.com/arsduo/koala for Ruby/Koala documentation
|
|
9
9
|
# and http://developers.facebook.com/docs/api for Facebook API documentation
|
|
10
|
-
#
|
|
10
|
+
#
|
|
11
11
|
# The Graph API is made up of the objects in Facebook (e.g., people, pages,
|
|
12
12
|
# events, photos) and the connections between them (e.g., friends,
|
|
13
13
|
# photo tags, and event RSVPs). This client provides access to those
|
|
14
14
|
# primitive types in a generic way. For example, given an OAuth access
|
|
15
15
|
# token, this will fetch the profile of the active user and the list
|
|
16
16
|
# of the user's friends:
|
|
17
|
-
#
|
|
18
|
-
# graph = Koala::Facebook::
|
|
17
|
+
#
|
|
18
|
+
# graph = Koala::Facebook::API.new(access_token)
|
|
19
19
|
# user = graph.get_object("me")
|
|
20
20
|
# friends = graph.get_connections(user["id"], "friends")
|
|
21
|
-
#
|
|
21
|
+
#
|
|
22
22
|
# You can see a list of all of the objects and connections supported
|
|
23
23
|
# by the API at http://developers.facebook.com/docs/reference/api/.
|
|
24
|
-
#
|
|
24
|
+
#
|
|
25
25
|
# You can obtain an access token via OAuth or by using the Facebook
|
|
26
26
|
# JavaScript SDK. See the Koala and Facebook documentation for more information.
|
|
27
|
-
#
|
|
27
|
+
#
|
|
28
28
|
# If you are using the JavaScript SDK, you can use the
|
|
29
29
|
# Koala::Facebook::OAuth.get_user_from_cookie() method below to get the OAuth access token
|
|
30
30
|
# for the active user from the cookie saved by the SDK.
|
|
@@ -35,19 +35,19 @@ module Koala
|
|
|
35
35
|
# Fetchs the given object from the graph.
|
|
36
36
|
graph_call(id, args, "get", options)
|
|
37
37
|
end
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
def get_objects(ids, args = {}, options = {})
|
|
40
40
|
# Fetchs all of the given objects from the graph.
|
|
41
41
|
# If any of the IDs are invalid, they'll raise an exception.
|
|
42
42
|
return [] if ids.empty?
|
|
43
43
|
graph_call("", args.merge("ids" => ids.respond_to?(:join) ? ids.join(",") : ids), "get", options)
|
|
44
44
|
end
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
def put_object(parent_object, connection_name, args = {}, options = {})
|
|
47
47
|
# Writes the given object to the graph, connected to the given parent.
|
|
48
48
|
# See http://developers.facebook.com/docs/api#publishing for all of
|
|
49
49
|
# the supported writeable objects.
|
|
50
|
-
#
|
|
50
|
+
#
|
|
51
51
|
# For example,
|
|
52
52
|
# graph.put_object("me", "feed", :message => "Hello, world")
|
|
53
53
|
# writes "Hello, world" to the active user's wall.
|
|
@@ -56,7 +56,7 @@ module Koala
|
|
|
56
56
|
# publishing wall posts requires the "publish_stream" permission. See
|
|
57
57
|
# http://developers.facebook.com/docs/authentication/ for details about
|
|
58
58
|
# extended permissions.
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
|
|
61
61
|
graph_call("#{parent_object}/#{connection_name}", args, "post", options)
|
|
62
62
|
end
|
|
@@ -66,24 +66,14 @@ module Koala
|
|
|
66
66
|
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Delete requires an access token"}) unless @access_token
|
|
67
67
|
graph_call(id, {}, "delete", options)
|
|
68
68
|
end
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# Connections
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
def get_connections(id, connection_name, args = {}, options = {})
|
|
73
73
|
# Fetchs the connections for given object.
|
|
74
|
-
graph_call("#{id}/#{connection_name}", args, "get", options)
|
|
75
|
-
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
|
76
|
-
end
|
|
74
|
+
graph_call("#{id}/#{connection_name}", args, "get", options)
|
|
77
75
|
end
|
|
78
76
|
|
|
79
|
-
def get_comments_for_urls(urls = [], args = {}, options = {})
|
|
80
|
-
# Fetchs the comments for given URLs (array or comma-separated string)
|
|
81
|
-
# see https://developers.facebook.com/blog/post/490
|
|
82
|
-
return [] if urls.empty?
|
|
83
|
-
args.merge!(:ids => urls.respond_to?(:join) ? urls.join(",") : urls)
|
|
84
|
-
get_object("comments", args, options)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
77
|
def put_connections(id, connection_name, args = {}, options = {})
|
|
88
78
|
# Posts a certain connection
|
|
89
79
|
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
|
|
@@ -98,19 +88,20 @@ module Koala
|
|
|
98
88
|
|
|
99
89
|
# Media (photos and videos)
|
|
100
90
|
# to delete photos or videos, use delete_object(object_id)
|
|
101
|
-
# note: you'll need the user_photos or user_videos permissions to actually access media after upload
|
|
102
|
-
|
|
91
|
+
# note: you'll need the user_photos or user_videos permissions to actually access media after upload
|
|
92
|
+
|
|
103
93
|
def get_picture(object, args = {}, options = {})
|
|
104
94
|
# Gets a picture object, returning the URL (which Facebook sends as a header)
|
|
105
95
|
graph_call("#{object}/picture", args, "get", options.merge(:http_component => :headers)) do |result|
|
|
106
96
|
result["Location"]
|
|
107
97
|
end
|
|
108
|
-
end
|
|
109
|
-
|
|
98
|
+
end
|
|
99
|
+
|
|
110
100
|
# Can be called in multiple ways:
|
|
111
101
|
#
|
|
112
102
|
# put_picture(file, [content_type], ...)
|
|
113
103
|
# put_picture(path_to_file, [content_type], ...)
|
|
104
|
+
# put_picture(picture_url, ...)
|
|
114
105
|
#
|
|
115
106
|
# You can pass in uploaded files directly from Rails or Sinatra.
|
|
116
107
|
# (See lib/koala/uploadable_io.rb for supported frameworks)
|
|
@@ -119,29 +110,32 @@ module Koala
|
|
|
119
110
|
# - args: a hash of request parameters (default: {})
|
|
120
111
|
# - target_id: ID of the target where to post the picture (default: "me")
|
|
121
112
|
# - options: a hash of http options passed to the HTTPService module
|
|
122
|
-
#
|
|
113
|
+
#
|
|
123
114
|
# put_picture(file, content_type, {:message => "Message"}, 01234560)
|
|
124
115
|
# put_picture(params[:file], {:message => "Message"})
|
|
125
|
-
|
|
116
|
+
#
|
|
117
|
+
# (Note that with URLs, there's no optional content type field)
|
|
118
|
+
# put_picture(picture_url, {:message => "Message"}, my_page_id)
|
|
119
|
+
|
|
126
120
|
def put_picture(*picture_args)
|
|
127
121
|
put_object(*parse_media_args(picture_args, "photos"))
|
|
128
122
|
end
|
|
129
|
-
|
|
123
|
+
|
|
130
124
|
def put_video(*video_args)
|
|
131
125
|
args = parse_media_args(video_args, "videos")
|
|
132
126
|
args.last[:video] = true
|
|
133
127
|
put_object(*args)
|
|
134
128
|
end
|
|
135
|
-
|
|
129
|
+
|
|
136
130
|
# Wall posts
|
|
137
131
|
# To get wall posts, use get_connections(user, "feed")
|
|
138
132
|
# To delete a wall post, just use delete_object(post_id)
|
|
139
|
-
|
|
133
|
+
|
|
140
134
|
def put_wall_post(message, attachment = {}, profile_id = "me", options = {})
|
|
141
135
|
# attachment is a hash describing the wall post
|
|
142
136
|
# (see X for more details)
|
|
143
|
-
# For instance,
|
|
144
|
-
#
|
|
137
|
+
# For instance,
|
|
138
|
+
#
|
|
145
139
|
# {"name" => "Link name"
|
|
146
140
|
# "link" => "http://www.example.com/",
|
|
147
141
|
# "caption" => "{*actor*} posted a new review",
|
|
@@ -150,19 +144,19 @@ module Koala
|
|
|
150
144
|
|
|
151
145
|
self.put_object(profile_id, "feed", attachment.merge({:message => message}), options)
|
|
152
146
|
end
|
|
153
|
-
|
|
147
|
+
|
|
154
148
|
# Comments
|
|
155
149
|
# to delete comments, use delete_object(comment_id)
|
|
156
150
|
# to get comments, use get_connections(object, "likes")
|
|
157
|
-
|
|
151
|
+
|
|
158
152
|
def put_comment(object_id, message, options = {})
|
|
159
153
|
# Writes the given comment on the given post.
|
|
160
154
|
self.put_object(object_id, "comments", {:message => message}, options)
|
|
161
155
|
end
|
|
162
|
-
|
|
156
|
+
|
|
163
157
|
# Likes
|
|
164
158
|
# to get likes, use get_connections(user, "likes")
|
|
165
|
-
|
|
159
|
+
|
|
166
160
|
def put_like(object_id, options = {})
|
|
167
161
|
# Likes the given post.
|
|
168
162
|
self.put_object(object_id, "likes", {}, options)
|
|
@@ -175,42 +169,44 @@ module Koala
|
|
|
175
169
|
end
|
|
176
170
|
|
|
177
171
|
# Search
|
|
178
|
-
|
|
172
|
+
|
|
179
173
|
def search(search_terms, args = {}, options = {})
|
|
180
174
|
args.merge!({:q => search_terms}) unless search_terms.nil?
|
|
181
|
-
graph_call("search", args, "get", options)
|
|
182
|
-
|
|
175
|
+
graph_call("search", args, "get", options)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Convenience Methods
|
|
179
|
+
|
|
180
|
+
def get_page_access_token(object_id)
|
|
181
|
+
result = get_object(object_id, :fields => "access_token") do
|
|
182
|
+
result ? result["access_token"] : nil
|
|
183
183
|
end
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def get_comments_for_urls(urls = [], args = {}, options = {})
|
|
187
|
+
# Fetchs the comments for given URLs (array or comma-separated string)
|
|
188
|
+
# see https://developers.facebook.com/blog/post/490
|
|
189
|
+
return [] if urls.empty?
|
|
190
|
+
args.merge!(:ids => urls.respond_to?(:join) ? urls.join(",") : urls)
|
|
191
|
+
get_object("comments", args, options)
|
|
192
|
+
end
|
|
193
|
+
|
|
187
194
|
# GraphCollection support
|
|
188
195
|
def get_page(params)
|
|
189
196
|
# Pages through a set of results stored in a GraphCollection
|
|
190
197
|
# Used for connections and search results
|
|
191
|
-
graph_call(*params)
|
|
192
|
-
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
|
193
|
-
end
|
|
198
|
+
graph_call(*params)
|
|
194
199
|
end
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
|
|
197
201
|
# Batch API
|
|
198
202
|
def batch(http_options = {}, &block)
|
|
199
|
-
batch_client = GraphBatchAPI.new(access_token)
|
|
203
|
+
batch_client = GraphBatchAPI.new(access_token, self)
|
|
200
204
|
if block
|
|
201
205
|
yield batch_client
|
|
202
206
|
batch_client.execute(http_options)
|
|
203
207
|
else
|
|
204
208
|
batch_client
|
|
205
209
|
end
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def self.included(base)
|
|
209
|
-
base.class_eval do
|
|
210
|
-
def self.batch
|
|
211
|
-
raise NoMethodError, "The BatchAPI signature has changed (the original implementation was not thread-safe). Please see https://github.com/arsduo/koala/wiki/Batch-requests. (This message will be removed in the final 1.1 release.)"
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
210
|
end
|
|
215
211
|
|
|
216
212
|
# Direct access to the Facebook API
|
|
@@ -221,38 +217,54 @@ module Koala
|
|
|
221
217
|
raise error if error
|
|
222
218
|
end
|
|
223
219
|
|
|
224
|
-
#
|
|
220
|
+
# turn this into a GraphCollection if it's pageable
|
|
221
|
+
result = GraphCollection.evaluate(result, self)
|
|
222
|
+
|
|
223
|
+
# now process as appropriate for the given call (get picture header, etc.)
|
|
225
224
|
post_processing ? post_processing.call(result) : result
|
|
226
225
|
end
|
|
226
|
+
|
|
227
|
+
private
|
|
227
228
|
|
|
228
229
|
def check_response(response)
|
|
229
230
|
# check for Graph API-specific errors
|
|
230
231
|
# this returns an error, which is immediately raised (non-batch)
|
|
231
232
|
# or added to the list of batch results (batch)
|
|
232
233
|
if response.is_a?(Hash) && error_details = response["error"]
|
|
233
|
-
APIError.new(error_details)
|
|
234
|
+
APIError.new(error_details)
|
|
234
235
|
end
|
|
235
236
|
end
|
|
236
|
-
|
|
237
|
-
private
|
|
238
|
-
|
|
237
|
+
|
|
239
238
|
def parse_media_args(media_args, method)
|
|
240
239
|
# photo and video uploads can accept different types of arguments (see above)
|
|
241
240
|
# so here, we parse the arguments into a form directly usable in put_object
|
|
242
241
|
raise KoalaError.new("Wrong number of arguments for put_#{method == "photos" ? "picture" : "video"}") unless media_args.size.between?(1, 5)
|
|
243
|
-
|
|
242
|
+
|
|
244
243
|
args_offset = media_args[1].kind_of?(Hash) || media_args.size == 1 ? 0 : 1
|
|
245
|
-
|
|
244
|
+
|
|
246
245
|
args = media_args[1 + args_offset] || {}
|
|
247
246
|
target_id = media_args[2 + args_offset] || "me"
|
|
248
|
-
options = media_args[3 + args_offset] || {}
|
|
249
|
-
|
|
250
|
-
args["source"] = Koala::UploadableIO.new(*media_args.slice(0, 1 + args_offset))
|
|
247
|
+
options = media_args[3 + args_offset] || {}
|
|
251
248
|
|
|
252
|
-
|
|
249
|
+
if url?(media_args.first)
|
|
250
|
+
# If media_args is a URL, we can upload without UploadableIO
|
|
251
|
+
args.merge!(:url => media_args.first)
|
|
252
|
+
else
|
|
253
|
+
args["source"] = Koala::UploadableIO.new(*media_args.slice(0, 1 + args_offset))
|
|
254
|
+
end
|
|
253
255
|
|
|
254
256
|
[target_id, method, args, options]
|
|
255
|
-
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def url?(data)
|
|
260
|
+
return false unless data.is_a? String
|
|
261
|
+
begin
|
|
262
|
+
uri = URI.parse(data)
|
|
263
|
+
%w( http https ).include?(uri.scheme)
|
|
264
|
+
rescue URI::BadURIError
|
|
265
|
+
false
|
|
266
|
+
end
|
|
267
|
+
end
|
|
256
268
|
end
|
|
257
269
|
end
|
|
258
|
-
end
|
|
270
|
+
end
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
module Koala
|
|
2
2
|
module Facebook
|
|
3
3
|
module GraphBatchAPIMethods
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
def self.included(base)
|
|
6
6
|
base.class_eval do
|
|
7
|
+
attr_reader :original_api
|
|
8
|
+
|
|
9
|
+
def initialize(access_token, api)
|
|
10
|
+
super(access_token)
|
|
11
|
+
@original_api = api
|
|
12
|
+
end
|
|
13
|
+
|
|
7
14
|
alias_method :graph_call_outside_batch, :graph_call
|
|
8
15
|
alias_method :graph_call, :graph_call_in_batch
|
|
9
|
-
|
|
16
|
+
|
|
10
17
|
alias_method :check_graph_api_response, :check_response
|
|
11
18
|
alias_method :check_response, :check_graph_batch_api_response
|
|
12
19
|
end
|
|
13
20
|
end
|
|
14
|
-
|
|
21
|
+
|
|
15
22
|
def batch_calls
|
|
16
23
|
@batch_calls ||= []
|
|
17
24
|
end
|
|
18
|
-
|
|
25
|
+
|
|
19
26
|
def graph_call_in_batch(path, args = {}, verb = "get", options = {}, &post_processing)
|
|
20
27
|
# for batch APIs, we queue up the call details (incl. post-processing)
|
|
21
28
|
batch_calls << BatchOperation.new(
|
|
@@ -26,7 +33,7 @@ module Koala
|
|
|
26
33
|
:http_options => options,
|
|
27
34
|
:post_processing => post_processing
|
|
28
35
|
)
|
|
29
|
-
nil # batch operations return nothing immediately
|
|
36
|
+
nil # batch operations return nothing immediately
|
|
30
37
|
end
|
|
31
38
|
|
|
32
39
|
def check_graph_batch_api_response(response)
|
|
@@ -45,8 +52,8 @@ module Koala
|
|
|
45
52
|
args.merge!(batch_op.files) if batch_op.files
|
|
46
53
|
batch_op.to_batch_params(access_token)
|
|
47
54
|
})
|
|
48
|
-
|
|
49
|
-
graph_call_outside_batch('/', args, 'post', http_options) do |response|
|
|
55
|
+
|
|
56
|
+
batch_result = graph_call_outside_batch('/', args, 'post', http_options) do |response|
|
|
50
57
|
# map the results with post-processing included
|
|
51
58
|
index = 0 # keep compat with ruby 1.8 - no with_index for map
|
|
52
59
|
response.map do |call_result|
|
|
@@ -57,10 +64,10 @@ module Koala
|
|
|
57
64
|
if call_result
|
|
58
65
|
# (see note in regular api method about JSON parsing)
|
|
59
66
|
body = MultiJson.decode("[#{call_result['body'].to_s}]")[0]
|
|
60
|
-
|
|
67
|
+
|
|
61
68
|
unless call_result["code"].to_i >= 500 || error = check_response(body)
|
|
62
69
|
# Get the HTTP component they want
|
|
63
|
-
data = case batch_op.http_options[:http_component]
|
|
70
|
+
data = case batch_op.http_options[:http_component]
|
|
64
71
|
when :status
|
|
65
72
|
call_result["code"].to_i
|
|
66
73
|
when :headers
|
|
@@ -78,10 +85,13 @@ module Koala
|
|
|
78
85
|
else
|
|
79
86
|
nil
|
|
80
87
|
end
|
|
81
|
-
end
|
|
88
|
+
end
|
|
82
89
|
end
|
|
90
|
+
|
|
91
|
+
# turn any results that are pageable into GraphCollections
|
|
92
|
+
batch_result.inject([]) {|processed_results, raw| processed_results << GraphCollection.evaluate(raw, @original_api)}
|
|
83
93
|
end
|
|
84
|
-
|
|
94
|
+
|
|
85
95
|
end
|
|
86
96
|
end
|
|
87
97
|
end
|
|
@@ -10,25 +10,30 @@ module Koala
|
|
|
10
10
|
# It also allows access to paging information and the
|
|
11
11
|
# ability to get the next/previous page in the collection
|
|
12
12
|
# by calling next_page or previous_page.
|
|
13
|
-
attr_reader :paging
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
attr_reader :paging, :api, :raw_response
|
|
14
|
+
|
|
15
|
+
def self.evaluate(response, api)
|
|
16
|
+
# turn the response into a GraphCollection if it's pageable; if not, return the original response
|
|
17
|
+
response.is_a?(Hash) && response["data"].is_a?(Array) ? self.new(response, api) : response
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
def initialize(response, api)
|
|
17
21
|
super response["data"]
|
|
18
22
|
@paging = response["paging"]
|
|
23
|
+
@raw_response = response
|
|
19
24
|
@api = api
|
|
20
25
|
end
|
|
21
|
-
|
|
26
|
+
|
|
22
27
|
# defines methods for NEXT and PREVIOUS pages
|
|
23
28
|
%w{next previous}.each do |this|
|
|
24
|
-
|
|
29
|
+
|
|
25
30
|
# def next_page
|
|
26
31
|
# def previous_page
|
|
27
32
|
define_method "#{this.to_sym}_page" do
|
|
28
33
|
base, args = send("#{this}_page_params")
|
|
29
34
|
base ? @api.get_page([base, args]) : nil
|
|
30
35
|
end
|
|
31
|
-
|
|
36
|
+
|
|
32
37
|
# def next_page_params
|
|
33
38
|
# def previous_page_params
|
|
34
39
|
define_method "#{this.to_sym}_page_params" do
|
|
@@ -36,7 +41,7 @@ module Koala
|
|
|
36
41
|
parse_page_url(@paging[this])
|
|
37
42
|
end
|
|
38
43
|
end
|
|
39
|
-
|
|
44
|
+
|
|
40
45
|
def parse_page_url(url)
|
|
41
46
|
match = url.match(/.com\/(.*)\?(.*)/)
|
|
42
47
|
base = match[1]
|
|
@@ -48,7 +53,7 @@ module Koala
|
|
|
48
53
|
end
|
|
49
54
|
[base,new_params]
|
|
50
55
|
end
|
|
51
|
-
|
|
56
|
+
|
|
52
57
|
end
|
|
53
58
|
end
|
|
54
59
|
end
|