koala 1.1.0 → 1.2.0beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -1
- data/CHANGELOG +26 -0
- data/Gemfile +6 -2
- data/Rakefile +0 -1
- data/koala.gemspec +8 -8
- data/lib/koala.rb +42 -45
- data/lib/koala/batch_operation.rb +15 -15
- data/lib/koala/graph_api.rb +81 -58
- data/lib/koala/graph_batch_api.rb +10 -10
- data/lib/koala/graph_collection.rb +6 -6
- data/lib/koala/http_service.rb +177 -0
- data/lib/koala/oauth.rb +2 -2
- data/lib/koala/realtime_updates.rb +20 -17
- data/lib/koala/rest_api.rb +1 -1
- data/lib/koala/test_users.rb +33 -16
- data/lib/koala/uploadable_io.rb +47 -42
- data/lib/koala/utils.rb +11 -0
- data/readme.md +38 -38
- data/spec/cases/api_base_spec.rb +2 -2
- data/spec/cases/error_spec.rb +32 -0
- data/spec/cases/graph_and_rest_api_spec.rb +20 -3
- data/spec/cases/graph_api_batch_spec.rb +88 -97
- data/spec/cases/graph_api_spec.rb +21 -4
- data/spec/cases/http_service_spec.rb +446 -0
- data/spec/cases/koala_spec.rb +33 -38
- data/spec/cases/oauth_spec.rb +219 -200
- 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 +112 -52
- data/spec/cases/uploadable_io_spec.rb +49 -36
- data/spec/cases/utils_spec.rb +10 -0
- data/spec/fixtures/facebook_data.yml +23 -22
- data/spec/fixtures/mock_facebook_responses.yml +126 -96
- data/spec/spec_helper.rb +29 -5
- data/spec/support/graph_api_shared_examples.rb +59 -52
- data/spec/support/json_testing_fix.rb +35 -11
- data/spec/support/koala_test.rb +163 -0
- data/spec/support/mock_http_service.rb +6 -4
- 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 +78 -79
- data/lib/koala/http_services.rb +0 -46
- data/lib/koala/http_services/net_http_service.rb +0 -92
- data/lib/koala/http_services/typhoeus_service.rb +0 -37
- 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,29 @@
|
|
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
|
+
Updated methods:
|
8
|
+
-- API.put_picture now accepts URLs to images (thanks, marcgg!)
|
9
|
+
Internal improvements:
|
10
|
+
-- Koala now uses Faraday to make requests, replacing the HTTPServices (see wiki)
|
11
|
+
-- Koala::HTTPService.http_options allows specification of default Faraday connection options
|
12
|
+
-- Koala::HTTPService.faraday_middleware allows custom middleware configurations
|
13
|
+
-- Koala now defaults to Net::HTTP rather than Typhoeus
|
14
|
+
-- Koala::NetHTTPService and Koala::TyphoeusService modules no longer exist
|
15
|
+
-- Koala no longer automatically switches to Net::HTTP when uploading IO objects to Facebook
|
16
|
+
-- RealTimeUpdates and TestUsers are no longer subclasses of API, but have their own .api objects
|
17
|
+
-- The old .graph_api accessor is aliases to .api with a deprecation warning
|
18
|
+
Testing improvements:
|
19
|
+
-- Live test suites now run against test users by default
|
20
|
+
-- Test suite can be repeatedly run live without having to update facebook_data.yml
|
21
|
+
-- OAuth code and session key tests cannot be run against test users
|
22
|
+
-- Faraday adapter for live tests can be specified with ADAPTER=[your adapter] in the shell command
|
23
|
+
-- Tests now pass against all rubies on Travis CI
|
24
|
+
-- Expanded test coverage
|
25
|
+
-- Fixed bug with YAML parsing in Ruby 1.9
|
26
|
+
|
1
27
|
v1.1
|
2
28
|
New methods:
|
3
29
|
-- Added Batch API support (thanks, seejohnrun and spiegela!)
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/koala.gemspec
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{koala}
|
5
|
-
s.version = "1.
|
6
|
-
s.date = %q{2011-
|
5
|
+
s.version = "1.2.0beta1"
|
6
|
+
s.date = %q{2011-08-17}
|
7
7
|
|
8
8
|
s.summary = %q{A lightweight, flexible library for Facebook with support for the Graph API, the REST API, realtime updates, and OAuth authentication.}
|
9
9
|
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 +29,22 @@ Gem::Specification.new do |s|
|
|
29
29
|
|
30
30
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
31
31
|
s.add_runtime_dependency(%q<multi_json>, ["~> 1.0"])
|
32
|
-
s.add_runtime_dependency(%q<
|
32
|
+
s.add_runtime_dependency(%q<faraday>, ["~> 0.7.4"])
|
33
|
+
s.add_runtime_dependency(%q<faraday-stack>, ["~> 0.1.3"])
|
33
34
|
s.add_development_dependency(%q<rspec>, ["~> 2.5"])
|
34
35
|
s.add_development_dependency(%q<rake>, ["~> 0.8.7"])
|
35
|
-
s.add_development_dependency(%q<typhoeus>, ["~> 0.2.4"])
|
36
36
|
else
|
37
37
|
s.add_dependency(%q<multi_json>, ["~> 1.0"])
|
38
|
-
s.add_dependency(%q<multipart-post>, ["~> 1.0"])
|
39
38
|
s.add_dependency(%q<rspec>, ["~> 2.5"])
|
40
39
|
s.add_dependency(%q<rake>, ["~> 0.8.7"])
|
41
|
-
s.add_dependency(%q<
|
40
|
+
s.add_dependency(%q<faraday>, ["~> 0.7.4"])
|
41
|
+
s.add_dependency(%q<faraday-stack>, ["~> 0.1.3"])
|
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.4"])
|
48
|
+
s.add_dependency(%q<faraday-stack>, ["~> 0.1.3"])
|
49
49
|
end
|
50
50
|
end
|
data/lib/koala.rb
CHANGED
@@ -8,8 +8,7 @@ require 'openssl'
|
|
8
8
|
require 'base64'
|
9
9
|
|
10
10
|
# include koala modules
|
11
|
-
require 'koala/
|
12
|
-
require 'koala/http_services/net_http_service'
|
11
|
+
require 'koala/http_service'
|
13
12
|
require 'koala/oauth'
|
14
13
|
require 'koala/graph_api'
|
15
14
|
require 'koala/graph_batch_api'
|
@@ -18,7 +17,7 @@ require 'koala/graph_collection'
|
|
18
17
|
require 'koala/rest_api'
|
19
18
|
require 'koala/realtime_updates'
|
20
19
|
require 'koala/test_users'
|
21
|
-
require 'koala/
|
20
|
+
require 'koala/utils'
|
22
21
|
|
23
22
|
# add KoalaIO class
|
24
23
|
require 'koala/uploadable_io'
|
@@ -31,6 +30,7 @@ module Koala
|
|
31
30
|
# Contributors: Alex Koppel, Chris Baclig, Rafi Jacoby, and the team at Context Optional
|
32
31
|
# http://github.com/arsduo/koala
|
33
32
|
|
33
|
+
# APIs
|
34
34
|
class API
|
35
35
|
# initialize with an access token
|
36
36
|
def initialize(access_token = nil)
|
@@ -38,10 +38,13 @@ module Koala
|
|
38
38
|
end
|
39
39
|
attr_reader :access_token
|
40
40
|
|
41
|
+
include GraphAPIMethods
|
42
|
+
include RestAPIMethods
|
43
|
+
|
41
44
|
def api(path, args = {}, verb = "get", options = {}, &error_checking_block)
|
42
45
|
# Fetches the given path in the Graph API.
|
43
46
|
args["access_token"] = @access_token || @app_access_token if @access_token || @app_access_token
|
44
|
-
|
47
|
+
|
45
48
|
# add a leading /
|
46
49
|
path = "/#{path}" unless path =~ /^\//
|
47
50
|
|
@@ -64,35 +67,30 @@ module Koala
|
|
64
67
|
end
|
65
68
|
end
|
66
69
|
|
67
|
-
# APIs
|
68
|
-
|
69
|
-
|
70
|
-
include GraphAPIMethods
|
71
|
-
end
|
72
|
-
|
73
|
-
class GraphBatchAPI < GraphAPI
|
74
|
-
include GraphBatchAPIMethods
|
75
|
-
end
|
76
|
-
|
77
|
-
class RestAPI < API
|
78
|
-
include RestAPIMethods
|
79
|
-
end
|
80
|
-
|
81
|
-
class GraphAndRestAPI < API
|
82
|
-
include GraphAPIMethods
|
83
|
-
include RestAPIMethods
|
70
|
+
# special enhanced APIs
|
71
|
+
class GraphBatchAPI < API
|
72
|
+
include GraphBatchAPIMethods
|
84
73
|
end
|
85
74
|
|
86
|
-
class RealtimeUpdates
|
75
|
+
class RealtimeUpdates
|
87
76
|
include RealtimeUpdateMethods
|
88
77
|
end
|
89
78
|
|
90
|
-
class TestUsers
|
79
|
+
class TestUsers
|
91
80
|
include TestUserMethods
|
92
|
-
# make the Graph API accessible in case someone wants to make other calls to interact with their users
|
93
|
-
attr_reader :graph_api
|
94
81
|
end
|
95
82
|
|
83
|
+
# legacy support for old APIs
|
84
|
+
class OldAPI < API;
|
85
|
+
def initialize(*args)
|
86
|
+
Koala::Utils.deprecate("#{self.class.name} is deprecated and will be removed in a future version; please use the API class instead.")
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
class GraphAPI < OldAPI; end
|
91
|
+
class RestAPI < OldAPI; end
|
92
|
+
class GraphAndRestAPI < OldAPI; end
|
93
|
+
|
96
94
|
# Errors
|
97
95
|
|
98
96
|
class APIError < StandardError
|
@@ -106,29 +104,28 @@ module Koala
|
|
106
104
|
|
107
105
|
class KoalaError < StandardError; end
|
108
106
|
|
109
|
-
# Make an api request using the provided api service or one passed by the caller
|
110
|
-
def self.make_request(path, args, verb, options = {})
|
111
|
-
http_service = options.delete(:http_service) || Koala.http_service
|
112
|
-
options = options.merge(:use_ssl => true) if @always_use_ssl
|
113
|
-
http_service.make_request(path, args, verb, options)
|
114
|
-
end
|
115
107
|
|
116
|
-
# finally,
|
117
|
-
# you can use your own (for HTTParty, etc.) by calling Koala.http_service = YourModule
|
108
|
+
# finally, the few things defined on the Koala module itself
|
118
109
|
class << self
|
119
110
|
attr_accessor :http_service
|
120
|
-
attr_accessor :always_use_ssl
|
121
|
-
attr_accessor :base_http_service
|
122
111
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
112
|
+
|
113
|
+
def self.http_service=(service)
|
114
|
+
if service.respond_to?(:deprecated_interface)
|
115
|
+
# if this is a deprecated module, support the old interface
|
116
|
+
# by changing the default adapter so the right library is used
|
117
|
+
# we continue to use the single HTTPService module for everything
|
118
|
+
service.deprecated_interface
|
119
|
+
else
|
120
|
+
# if it's a real http_service, use it
|
121
|
+
@http_service = service
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.make_request(path, args, verb, options = {})
|
126
|
+
http_service.make_request(path, args, verb, options)
|
133
127
|
end
|
128
|
+
|
129
|
+
# we use Faraday as our main service, with mock as the other main one
|
130
|
+
self.http_service = HTTPService
|
134
131
|
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,9 +66,9 @@ 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
74
|
graph_call("#{id}/#{connection_name}", args, "get", options) do |result|
|
@@ -76,14 +76,6 @@ module Koala
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
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
79
|
def put_connections(id, connection_name, args = {}, options = {})
|
88
80
|
# Posts a certain connection
|
89
81
|
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
|
@@ -98,19 +90,20 @@ module Koala
|
|
98
90
|
|
99
91
|
# Media (photos and videos)
|
100
92
|
# 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
|
-
|
93
|
+
# note: you'll need the user_photos or user_videos permissions to actually access media after upload
|
94
|
+
|
103
95
|
def get_picture(object, args = {}, options = {})
|
104
96
|
# Gets a picture object, returning the URL (which Facebook sends as a header)
|
105
97
|
graph_call("#{object}/picture", args, "get", options.merge(:http_component => :headers)) do |result|
|
106
98
|
result["Location"]
|
107
99
|
end
|
108
|
-
end
|
109
|
-
|
100
|
+
end
|
101
|
+
|
110
102
|
# Can be called in multiple ways:
|
111
103
|
#
|
112
104
|
# put_picture(file, [content_type], ...)
|
113
105
|
# put_picture(path_to_file, [content_type], ...)
|
106
|
+
# put_picture(picture_url, ...)
|
114
107
|
#
|
115
108
|
# You can pass in uploaded files directly from Rails or Sinatra.
|
116
109
|
# (See lib/koala/uploadable_io.rb for supported frameworks)
|
@@ -119,29 +112,32 @@ module Koala
|
|
119
112
|
# - args: a hash of request parameters (default: {})
|
120
113
|
# - target_id: ID of the target where to post the picture (default: "me")
|
121
114
|
# - options: a hash of http options passed to the HTTPService module
|
122
|
-
#
|
115
|
+
#
|
123
116
|
# put_picture(file, content_type, {:message => "Message"}, 01234560)
|
124
117
|
# put_picture(params[:file], {:message => "Message"})
|
125
|
-
|
118
|
+
#
|
119
|
+
# (Note that with URLs, there's no optional content type field)
|
120
|
+
# put_picture(picture_url, {:message => "Message"}, my_page_id)
|
121
|
+
|
126
122
|
def put_picture(*picture_args)
|
127
123
|
put_object(*parse_media_args(picture_args, "photos"))
|
128
124
|
end
|
129
|
-
|
125
|
+
|
130
126
|
def put_video(*video_args)
|
131
127
|
args = parse_media_args(video_args, "videos")
|
132
128
|
args.last[:video] = true
|
133
129
|
put_object(*args)
|
134
130
|
end
|
135
|
-
|
131
|
+
|
136
132
|
# Wall posts
|
137
133
|
# To get wall posts, use get_connections(user, "feed")
|
138
134
|
# To delete a wall post, just use delete_object(post_id)
|
139
|
-
|
135
|
+
|
140
136
|
def put_wall_post(message, attachment = {}, profile_id = "me", options = {})
|
141
137
|
# attachment is a hash describing the wall post
|
142
138
|
# (see X for more details)
|
143
|
-
# For instance,
|
144
|
-
#
|
139
|
+
# For instance,
|
140
|
+
#
|
145
141
|
# {"name" => "Link name"
|
146
142
|
# "link" => "http://www.example.com/",
|
147
143
|
# "caption" => "{*actor*} posted a new review",
|
@@ -150,19 +146,19 @@ module Koala
|
|
150
146
|
|
151
147
|
self.put_object(profile_id, "feed", attachment.merge({:message => message}), options)
|
152
148
|
end
|
153
|
-
|
149
|
+
|
154
150
|
# Comments
|
155
151
|
# to delete comments, use delete_object(comment_id)
|
156
152
|
# to get comments, use get_connections(object, "likes")
|
157
|
-
|
153
|
+
|
158
154
|
def put_comment(object_id, message, options = {})
|
159
155
|
# Writes the given comment on the given post.
|
160
156
|
self.put_object(object_id, "comments", {:message => message}, options)
|
161
157
|
end
|
162
|
-
|
158
|
+
|
163
159
|
# Likes
|
164
160
|
# to get likes, use get_connections(user, "likes")
|
165
|
-
|
161
|
+
|
166
162
|
def put_like(object_id, options = {})
|
167
163
|
# Likes the given post.
|
168
164
|
self.put_object(object_id, "likes", {}, options)
|
@@ -175,15 +171,30 @@ module Koala
|
|
175
171
|
end
|
176
172
|
|
177
173
|
# Search
|
178
|
-
|
174
|
+
|
179
175
|
def search(search_terms, args = {}, options = {})
|
180
176
|
args.merge!({:q => search_terms}) unless search_terms.nil?
|
181
177
|
graph_call("search", args, "get", options) do |result|
|
182
178
|
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
183
179
|
end
|
184
|
-
end
|
185
|
-
|
186
|
-
|
180
|
+
end
|
181
|
+
|
182
|
+
# Convenience Methods
|
183
|
+
|
184
|
+
def get_page_access_token(object_id)
|
185
|
+
result = get_object(object_id, :fields => "access_token") do
|
186
|
+
result ? result["access_token"] : nil
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def get_comments_for_urls(urls = [], args = {}, options = {})
|
191
|
+
# Fetchs the comments for given URLs (array or comma-separated string)
|
192
|
+
# see https://developers.facebook.com/blog/post/490
|
193
|
+
return [] if urls.empty?
|
194
|
+
args.merge!(:ids => urls.respond_to?(:join) ? urls.join(",") : urls)
|
195
|
+
get_object("comments", args, options)
|
196
|
+
end
|
197
|
+
|
187
198
|
# GraphCollection support
|
188
199
|
def get_page(params)
|
189
200
|
# Pages through a set of results stored in a GraphCollection
|
@@ -192,8 +203,7 @@ module Koala
|
|
192
203
|
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
193
204
|
end
|
194
205
|
end
|
195
|
-
|
196
|
-
|
206
|
+
|
197
207
|
# Batch API
|
198
208
|
def batch(http_options = {}, &block)
|
199
209
|
batch_client = GraphBatchAPI.new(access_token)
|
@@ -203,8 +213,8 @@ module Koala
|
|
203
213
|
else
|
204
214
|
batch_client
|
205
215
|
end
|
206
|
-
end
|
207
|
-
|
216
|
+
end
|
217
|
+
|
208
218
|
def self.included(base)
|
209
219
|
base.class_eval do
|
210
220
|
def self.batch
|
@@ -212,7 +222,7 @@ module Koala
|
|
212
222
|
end
|
213
223
|
end
|
214
224
|
end
|
215
|
-
|
225
|
+
|
216
226
|
# Direct access to the Facebook API
|
217
227
|
# see any of the above methods for example invocations
|
218
228
|
def graph_call(path, args = {}, verb = "get", options = {}, &post_processing)
|
@@ -224,35 +234,48 @@ module Koala
|
|
224
234
|
# now process as appropriate (get picture header, make GraphCollection, etc.)
|
225
235
|
post_processing ? post_processing.call(result) : result
|
226
236
|
end
|
227
|
-
|
237
|
+
|
228
238
|
def check_response(response)
|
229
239
|
# check for Graph API-specific errors
|
230
240
|
# this returns an error, which is immediately raised (non-batch)
|
231
241
|
# or added to the list of batch results (batch)
|
232
242
|
if response.is_a?(Hash) && error_details = response["error"]
|
233
|
-
APIError.new(error_details)
|
243
|
+
APIError.new(error_details)
|
234
244
|
end
|
235
245
|
end
|
236
|
-
|
246
|
+
|
237
247
|
private
|
238
|
-
|
248
|
+
|
239
249
|
def parse_media_args(media_args, method)
|
240
250
|
# photo and video uploads can accept different types of arguments (see above)
|
241
251
|
# so here, we parse the arguments into a form directly usable in put_object
|
242
252
|
raise KoalaError.new("Wrong number of arguments for put_#{method == "photos" ? "picture" : "video"}") unless media_args.size.between?(1, 5)
|
243
|
-
|
253
|
+
|
244
254
|
args_offset = media_args[1].kind_of?(Hash) || media_args.size == 1 ? 0 : 1
|
245
|
-
|
255
|
+
|
246
256
|
args = media_args[1 + args_offset] || {}
|
247
257
|
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))
|
258
|
+
options = media_args[3 + args_offset] || {}
|
251
259
|
|
252
|
-
|
260
|
+
if url?(media_args.first)
|
261
|
+
# If media_args is a URL, we can upload without UploadableIO
|
262
|
+
args.merge!(:url => media_args.first)
|
263
|
+
else
|
264
|
+
args["source"] = Koala::UploadableIO.new(*media_args.slice(0, 1 + args_offset))
|
265
|
+
end
|
253
266
|
|
254
267
|
[target_id, method, args, options]
|
255
|
-
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def url?(data)
|
271
|
+
return false unless data.is_a? String
|
272
|
+
begin
|
273
|
+
uri = URI.parse(data)
|
274
|
+
%w( http https ).include?(uri.scheme)
|
275
|
+
rescue URI::BadURIError
|
276
|
+
false
|
277
|
+
end
|
278
|
+
end
|
256
279
|
end
|
257
280
|
end
|
258
|
-
end
|
281
|
+
end
|