koala 0.10.0 → 1.0.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/.gitignore +3 -0
- data/CHANGELOG +37 -7
- data/Gemfile +3 -0
- data/LICENSE +1 -1
- data/Manifest +8 -1
- data/Rakefile +13 -14
- data/koala.gemspec +36 -19
- data/lib/koala/graph_api.rb +188 -123
- data/lib/koala/http_services.rb +93 -18
- data/lib/koala/rest_api.rb +73 -6
- data/lib/koala/test_users.rb +21 -8
- data/lib/koala/uploadable_io.rb +115 -0
- data/lib/koala.rb +104 -120
- data/readme.md +29 -16
- data/spec/cases/api_base_spec.rb +101 -0
- data/spec/cases/graph_and_rest_api_spec.rb +31 -0
- data/spec/cases/graph_api_spec.rb +25 -0
- data/spec/cases/http_services/http_service_spec.rb +54 -0
- data/spec/cases/http_services/net_http_service_spec.rb +350 -0
- data/spec/cases/http_services/typhoeus_service_spec.rb +144 -0
- data/spec/cases/oauth_spec.rb +409 -0
- data/spec/cases/realtime_updates_spec.rb +184 -0
- data/spec/cases/rest_api_spec.rb +25 -0
- data/spec/{koala/test_users/test_users_tests.rb → cases/test_users_spec.rb} +78 -72
- data/spec/cases/uploadable_io_spec.rb +151 -0
- data/spec/fixtures/beach.jpg +0 -0
- data/spec/{facebook_data.yml → fixtures/facebook_data.yml} +13 -9
- data/spec/{mock_facebook_responses.yml → fixtures/mock_facebook_responses.yml} +314 -289
- data/spec/spec_helper.rb +18 -0
- data/spec/support/graph_api_shared_examples.rb +424 -0
- data/spec/{koala → support}/live_testing_data_helper.rb +39 -42
- data/spec/{mock_http_service.rb → support/mock_http_service.rb} +94 -81
- data/spec/support/rest_api_shared_examples.rb +161 -0
- data/spec/support/setup_mocks_or_live.rb +52 -0
- data/spec/support/uploadable_io_shared_examples.rb +76 -0
- metadata +127 -43
- data/init.rb +0 -2
- data/spec/koala/api_base_tests.rb +0 -102
- data/spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb +0 -10
- data/spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb +0 -11
- data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +0 -114
- data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +0 -150
- data/spec/koala/graph_api/graph_collection_tests.rb +0 -104
- data/spec/koala/net_http_service_tests.rb +0 -186
- data/spec/koala/oauth/oauth_tests.rb +0 -438
- data/spec/koala/realtime_updates/realtime_updates_tests.rb +0 -187
- data/spec/koala/rest_api/rest_api_no_access_token_tests.rb +0 -94
- data/spec/koala/rest_api/rest_api_with_access_token_tests.rb +0 -36
- data/spec/koala_spec.rb +0 -18
- data/spec/koala_spec_helper.rb +0 -48
- data/spec/koala_spec_without_mocks.rb +0 -19
data/.gitignore
ADDED
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
v1.0
|
|
2
|
+
New methods:
|
|
3
|
+
-- Photo and file upload now supported through #put_picture
|
|
4
|
+
-- Added UploadableIO class to manage file uploads
|
|
5
|
+
-- Added a delete_like method (thanks to waseem)
|
|
6
|
+
-- Added put_connection and delete_connection convenience methods
|
|
7
|
+
Updated methods:
|
|
8
|
+
-- Search can now search places, checkins, etc. (thanks, rickyc!)
|
|
9
|
+
-- You can now pass :beta => true in the http options to use Facebook's beta tier.
|
|
10
|
+
-- TestUser#befriend now requires user info hashes (id and access token) due to Facebook API changes (thanks, pulsd and kbighorse!)
|
|
11
|
+
-- All methods now accept an http_options hash as their optional last parameter (thanks, spiegela!)
|
|
12
|
+
-- url_for_oauth_code can now take a :display option (thanks, netbe!)
|
|
13
|
+
-- Net::HTTP can now accept :timeout and :proxy options (thanks, gilles!)
|
|
14
|
+
-- Test users now supports using test accounts across multiple apps
|
|
15
|
+
Internal improvements:
|
|
16
|
+
-- For public requests, Koala now uses http by default (instead of https) to improve speed
|
|
17
|
+
-- This can be overridden through Koala.always_use_ssl= or by passing :use_ssl => true in the options hash for an api call
|
|
18
|
+
-- Read-only REST API requests now go through the faster api-read server
|
|
19
|
+
-- Replaced parse_signed_request with a version from Facebook that also supports the new signed params proposal
|
|
20
|
+
-- Note: invalid requests will now raise exceptions rather than return nil, in keeping with other SDKs
|
|
21
|
+
-- Delete methods will now raise an error if there's no access token (like put_object and delete_like)
|
|
22
|
+
-- Updated parse_signed_request to match Facebook's current implementation (thanks, imajes!)
|
|
23
|
+
-- APIError is now < StandardError, not Exception
|
|
24
|
+
-- Added KoalaError for non-API errors
|
|
25
|
+
Test improvements:
|
|
26
|
+
-- Incorporated joshk's awesome rewrite of the entire Koala test suite (thanks, joshk!)
|
|
27
|
+
-- Expanded HTTP service tests (added Typhoeus test suite and additional Net::HTTP test cases)
|
|
28
|
+
-- Live tests now verify that the access token has the necessary permissions before starting
|
|
29
|
+
-- Replaced the 50-person network test, which often took 15+ minutes to run live, with a 5-person test
|
|
30
|
+
|
|
1
31
|
v0.10.0
|
|
2
32
|
-- Added test user module
|
|
3
33
|
-- Fixed bug when raising APIError after Facebook fails to exchange session keys
|
|
@@ -11,10 +41,10 @@ v0.9.1
|
|
|
11
41
|
v0.9.0
|
|
12
42
|
-- Added parse_signed_request to handle Facebook's new authentication scheme
|
|
13
43
|
-- note: creates dependency on OpenSSL (OpenSSL::HMAC) for decryption
|
|
14
|
-
-- Added GraphCollection class to provide paging support for GraphAPI get_connections and search methods (thanks to jagthedrummer)
|
|
44
|
+
-- Added GraphCollection class to provide paging support for GraphAPI get_connections and search methods (thanks to jagthedrummer)
|
|
15
45
|
-- Added get_page method to easily fetch pages of results from GraphCollections
|
|
16
46
|
-- Exchanging sessions for tokens now works properly when provided invalid/expired session keys
|
|
17
|
-
-- You can now include a :typhoeus_options key in TyphoeusService#make_request's options hash to control the Typhoeus call (for example, to set :disable_ssl_peer_verification => true)
|
|
47
|
+
-- You can now include a :typhoeus_options key in TyphoeusService#make_request's options hash to control the Typhoeus call (for example, to set :disable_ssl_peer_verification => true)
|
|
18
48
|
-- All paths provided to HTTP services start with leading / to improve compatibility with stubbing libraries
|
|
19
49
|
-- If Facebook returns nil for search or get_connections requests, Koala now returns nil rather than throwing an exception
|
|
20
50
|
|
|
@@ -23,7 +53,7 @@ v0.8.0
|
|
|
23
53
|
-- Removed string overloading for the methods, per 0.7.3, which caused Marshaling issues
|
|
24
54
|
-- Removed ability to provide a string as the second argument to url_for_access_token, per 0.5.0
|
|
25
55
|
|
|
26
|
-
v0.7.4
|
|
56
|
+
v0.7.4
|
|
27
57
|
-- Fixed bug with get_user_from_cookies
|
|
28
58
|
|
|
29
59
|
v0.7.3
|
|
@@ -34,18 +64,18 @@ v0.7.3
|
|
|
34
64
|
-- Using those methods triggers a deprecation warning
|
|
35
65
|
-- This will be removed by 1.0
|
|
36
66
|
-- There are new info methods (get_access_token_info, get_app_access_token_info, get_token_info_from_session_keys, and get_user_info_from_cookies) that natively return hashes, for when you want the expiration date
|
|
37
|
-
-- Responses with HTTP status 500+ now properly throw errors under Net::HTTP
|
|
67
|
+
-- Responses with HTTP status 500+ now properly throw errors under Net::HTTP
|
|
38
68
|
-- Updated changelog
|
|
39
69
|
-- Added license
|
|
40
70
|
|
|
41
71
|
v0.7.2
|
|
42
72
|
-- Added support for exchanging session keys for OAuth access tokens (get_token_from_session_key for single keys, get_tokens_from_session_keys for multiple)
|
|
43
73
|
-- Moved Koala files into a koala/ subdirectory to minimize risk of name collisions
|
|
44
|
-
-- Added OAuth Playground git submodule as an example
|
|
74
|
+
-- Added OAuth Playground git submodule as an example
|
|
45
75
|
-- Updated tests, readme, and changelog
|
|
46
76
|
|
|
47
77
|
v0.7.1
|
|
48
|
-
-- Updated RealtimeUpdates#list_subscriptions and GraphAPI#get_connections to now return an
|
|
78
|
+
-- Updated RealtimeUpdates#list_subscriptions and GraphAPI#get_connections to now return an
|
|
49
79
|
array of results directly (rather than a hash with one key)
|
|
50
80
|
-- Fixed a bug with Net::HTTP-based HTTP service in which the headers hash was improperly formatted
|
|
51
81
|
-- Updated readme
|
|
@@ -92,7 +122,7 @@ v0.3.1
|
|
|
92
122
|
v0.3
|
|
93
123
|
-- Renamed Graph API class from Facebook::GraphAPI to FacebookGraph::API
|
|
94
124
|
-- Created FacebookGraph::OAuth class for tokens and OAuth URLs
|
|
95
|
-
-- Updated method for including HTTP service (think we've got it this time)
|
|
125
|
+
-- Updated method for including HTTP service (think we've got it this time)
|
|
96
126
|
-- Updated tests
|
|
97
127
|
-- Added CHANGELOG and gemspec
|
|
98
128
|
|
data/Gemfile
ADDED
data/LICENSE
CHANGED
data/Manifest
CHANGED
|
@@ -10,21 +10,28 @@ lib/koala/http_services.rb
|
|
|
10
10
|
lib/koala/realtime_updates.rb
|
|
11
11
|
lib/koala/rest_api.rb
|
|
12
12
|
lib/koala/test_users.rb
|
|
13
|
+
lib/koala/uploadable_io.rb
|
|
13
14
|
readme.md
|
|
14
15
|
spec/facebook_data.yml
|
|
15
16
|
spec/koala/api_base_tests.rb
|
|
17
|
+
spec/koala/assets/beach.jpg
|
|
16
18
|
spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb
|
|
17
19
|
spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb
|
|
18
20
|
spec/koala/graph_api/graph_api_no_access_token_tests.rb
|
|
21
|
+
spec/koala/graph_api/graph_api_tests.rb
|
|
19
22
|
spec/koala/graph_api/graph_api_with_access_token_tests.rb
|
|
20
23
|
spec/koala/graph_api/graph_collection_tests.rb
|
|
24
|
+
spec/koala/http_services/http_service_tests.rb
|
|
25
|
+
spec/koala/http_services/net_http_service_tests.rb
|
|
26
|
+
spec/koala/http_services/typhoeus_service_tests.rb
|
|
21
27
|
spec/koala/live_testing_data_helper.rb
|
|
22
|
-
spec/koala/net_http_service_tests.rb
|
|
23
28
|
spec/koala/oauth/oauth_tests.rb
|
|
24
29
|
spec/koala/realtime_updates/realtime_updates_tests.rb
|
|
25
30
|
spec/koala/rest_api/rest_api_no_access_token_tests.rb
|
|
31
|
+
spec/koala/rest_api/rest_api_tests.rb
|
|
26
32
|
spec/koala/rest_api/rest_api_with_access_token_tests.rb
|
|
27
33
|
spec/koala/test_users/test_users_tests.rb
|
|
34
|
+
spec/koala/uploadable_io/uploadable_io_tests.rb
|
|
28
35
|
spec/koala_spec.rb
|
|
29
36
|
spec/koala_spec_helper.rb
|
|
30
37
|
spec/koala_spec_without_mocks.rb
|
data/Rakefile
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
# Rakefile
|
|
2
|
-
require 'rubygems'
|
|
3
1
|
require 'rake'
|
|
4
|
-
require 'echoe'
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
begin
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
Bundler::GemHelper.install_tasks
|
|
6
|
+
rescue LoadError
|
|
7
|
+
puts 'although not required, bundler is recommened for running the tests'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
task :default => :spec
|
|
12
|
+
|
|
13
|
+
require 'rspec/core/rake_task'
|
|
14
|
+
RSpec::Core::RakeTask.new do |t|
|
|
15
|
+
t.rspec_opts = ["--color", '--format doc']
|
|
17
16
|
end
|
data/koala.gemspec
CHANGED
|
@@ -1,33 +1,50 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
|
-
s.name
|
|
5
|
-
s.version = "0.
|
|
4
|
+
s.name = %q{koala}
|
|
5
|
+
s.version = "1.0.0"
|
|
6
|
+
s.date = %q{2011-05-01}
|
|
7
|
+
|
|
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
|
+
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.}
|
|
10
|
+
s.homepage = %q{http://github.com/arsduo/koala}
|
|
6
11
|
|
|
7
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
12
|
s.authors = ["Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional"]
|
|
9
|
-
s.
|
|
10
|
-
|
|
11
|
-
s.
|
|
12
|
-
s.
|
|
13
|
-
|
|
14
|
-
s.
|
|
15
|
-
s.rdoc_options
|
|
16
|
-
|
|
17
|
-
s.
|
|
18
|
-
|
|
19
|
-
s.
|
|
13
|
+
s.email = %q{alex@alexkoppel.com}
|
|
14
|
+
|
|
15
|
+
s.files = `git ls-files`.split("\n")
|
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
17
|
+
|
|
18
|
+
s.extra_rdoc_files = ["readme.md", "CHANGELOG"]
|
|
19
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Koala"]
|
|
20
|
+
|
|
21
|
+
s.require_paths = ["lib"]
|
|
22
|
+
|
|
23
|
+
s.rubygems_version = %q{1.4.2}
|
|
24
|
+
|
|
25
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
20
26
|
|
|
21
27
|
if s.respond_to? :specification_version then
|
|
22
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
23
28
|
s.specification_version = 3
|
|
24
29
|
|
|
25
|
-
if Gem::Version.new(Gem::
|
|
26
|
-
s.add_runtime_dependency(%q<json>,
|
|
30
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
31
|
+
s.add_runtime_dependency(%q<json>, ["~> 1.0"])
|
|
32
|
+
s.add_runtime_dependency(%q<multipart-post>, ["~> 1.0"])
|
|
33
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.5.0"])
|
|
34
|
+
s.add_development_dependency(%q<rake>, ["~> 0.8.7"])
|
|
35
|
+
s.add_development_dependency(%q<typhoeus>, ["~> 0.2.4"])
|
|
27
36
|
else
|
|
28
|
-
s.add_dependency(%q<json>,
|
|
37
|
+
s.add_dependency(%q<json>, ["~> 1.0"])
|
|
38
|
+
s.add_dependency(%q<multipart-post>, ["~> 1.0"])
|
|
39
|
+
s.add_dependency(%q<rspec>, ["~> 2.5.0"])
|
|
40
|
+
s.add_dependency(%q<rake>, ["~> 0.8.7"])
|
|
41
|
+
s.add_dependency(%q<typhoeus>, ["~> 0.2.4"])
|
|
29
42
|
end
|
|
30
43
|
else
|
|
31
|
-
s.add_dependency(%q<json>,
|
|
44
|
+
s.add_dependency(%q<json>, ["~> 1.0"])
|
|
45
|
+
s.add_dependency(%q<multipart-post>, ["~> 1.0"])
|
|
46
|
+
s.add_dependency(%q<rspec>, ["~> 2.5.0"])
|
|
47
|
+
s.add_dependency(%q<rake>, ["~> 0.8.7"])
|
|
48
|
+
s.add_dependency(%q<typhoeus>, ["~> 0.2.4"])
|
|
32
49
|
end
|
|
33
50
|
end
|
data/lib/koala/graph_api.rb
CHANGED
|
@@ -1,65 +1,12 @@
|
|
|
1
1
|
module Koala
|
|
2
2
|
module Facebook
|
|
3
|
-
GRAPH_SERVER = "graph.facebook.com"
|
|
4
|
-
|
|
5
|
-
class GraphCollection < Array
|
|
6
|
-
#This class is a light wrapper for collections returned
|
|
7
|
-
#from the Graph API.
|
|
8
|
-
#
|
|
9
|
-
#It extends Array to allow direct access to the data colleciton
|
|
10
|
-
#which should allow it to drop in seamlessly.
|
|
11
|
-
#
|
|
12
|
-
#It also allows access to paging information and the
|
|
13
|
-
#ability to get the next/previous page in the collection
|
|
14
|
-
#by calling next_page or previous_page.
|
|
15
|
-
attr_reader :paging
|
|
16
|
-
attr_reader :api
|
|
17
|
-
|
|
18
|
-
def initialize(response, api)
|
|
19
|
-
super response["data"]
|
|
20
|
-
@paging = response["paging"]
|
|
21
|
-
@api = api
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# defines methods for NEXT and PREVIOUS pages
|
|
25
|
-
%w{next previous}.each do |this|
|
|
26
|
-
|
|
27
|
-
# def next_page
|
|
28
|
-
# def previous_page
|
|
29
|
-
define_method "#{this.to_sym}_page" do
|
|
30
|
-
base, args = send("#{this}_page_params")
|
|
31
|
-
base ? @api.get_page([base, args]) : nil
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# def next_page_params
|
|
35
|
-
# def previous_page_params
|
|
36
|
-
define_method "#{this.to_sym}_page_params" do
|
|
37
|
-
return nil unless @paging and @paging[this]
|
|
38
|
-
parse_page_url(@paging[this])
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def parse_page_url(url)
|
|
43
|
-
match = url.match(/.com\/(.*)\?(.*)/)
|
|
44
|
-
base = match[1]
|
|
45
|
-
args = match[2]
|
|
46
|
-
params = CGI.parse(args)
|
|
47
|
-
new_params = {}
|
|
48
|
-
params.each_pair do |key,value|
|
|
49
|
-
new_params[key] = value.join ","
|
|
50
|
-
end
|
|
51
|
-
[base,new_params]
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
|
3
|
+
GRAPH_SERVER = "graph.facebook.com"
|
|
57
4
|
|
|
58
5
|
module GraphAPIMethods
|
|
59
6
|
# A client for the Facebook Graph API.
|
|
60
7
|
#
|
|
61
|
-
# See http://
|
|
62
|
-
# for
|
|
8
|
+
# See http://github.com/arsduo/koala for Ruby/Koala documentation
|
|
9
|
+
# and http://developers.facebook.com/docs/api for Facebook API documentation
|
|
63
10
|
#
|
|
64
11
|
# The Graph API is made up of the objects in Facebook (e.g., people, pages,
|
|
65
12
|
# events, photos) and the connections between them (e.g., friends,
|
|
@@ -76,108 +23,164 @@ module Koala
|
|
|
76
23
|
# by the API at http://developers.facebook.com/docs/reference/api/.
|
|
77
24
|
#
|
|
78
25
|
# You can obtain an access token via OAuth or by using the Facebook
|
|
79
|
-
# JavaScript SDK. See
|
|
80
|
-
# for details.
|
|
26
|
+
# JavaScript SDK. See the Koala and Facebook documentation for more information.
|
|
81
27
|
#
|
|
82
28
|
# If you are using the JavaScript SDK, you can use the
|
|
83
29
|
# Koala::Facebook::OAuth.get_user_from_cookie() method below to get the OAuth access token
|
|
84
30
|
# for the active user from the cookie saved by the SDK.
|
|
85
|
-
|
|
86
|
-
|
|
31
|
+
|
|
32
|
+
# Objects
|
|
33
|
+
|
|
34
|
+
def get_object(id, args = {}, options = {})
|
|
87
35
|
# Fetchs the given object from the graph.
|
|
88
|
-
graph_call(id, args)
|
|
36
|
+
graph_call(id, args, "get", options)
|
|
89
37
|
end
|
|
90
38
|
|
|
91
|
-
def get_objects(ids, args = {})
|
|
39
|
+
def get_objects(ids, args = {}, options = {})
|
|
92
40
|
# Fetchs all of the given object from the graph.
|
|
93
41
|
# We return a map from ID to object. If any of the IDs are invalid,
|
|
94
42
|
# we raise an exception.
|
|
95
|
-
graph_call("", args.merge("ids" => ids.join(",")))
|
|
43
|
+
graph_call("", args.merge("ids" => ids.join(",")), "get", options)
|
|
96
44
|
end
|
|
97
45
|
|
|
98
|
-
def
|
|
99
|
-
result = graph_call(*params)
|
|
100
|
-
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def get_connections(id, connection_name, args = {})
|
|
104
|
-
# Fetchs the connections for given object.
|
|
105
|
-
result = graph_call("#{id}/#{connection_name}", args)
|
|
106
|
-
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def get_picture(object, args = {})
|
|
111
|
-
result = graph_call("#{object}/picture", args, "get", :http_component => :headers)
|
|
112
|
-
result["Location"]
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def put_object(parent_object, connection_name, args = {})
|
|
46
|
+
def put_object(parent_object, connection_name, args = {}, options = {})
|
|
116
47
|
# Writes the given object to the graph, connected to the given parent.
|
|
117
|
-
#
|
|
118
|
-
# For example,
|
|
119
|
-
#
|
|
120
|
-
# graph.put_object("me", "feed", :message => "Hello, world")
|
|
121
|
-
#
|
|
122
|
-
# writes "Hello, world" to the active user's wall. Likewise, this
|
|
123
|
-
# will comment on a the first post of the active user's feed:
|
|
124
|
-
#
|
|
125
|
-
# feed = graph.get_connections("me", "feed")
|
|
126
|
-
# post = feed["data"][0]
|
|
127
|
-
# graph.put_object(post["id"], "comments", :message => "First!")
|
|
128
|
-
#
|
|
129
48
|
# See http://developers.facebook.com/docs/api#publishing for all of
|
|
130
49
|
# the supported writeable objects.
|
|
131
50
|
#
|
|
51
|
+
# For example,
|
|
52
|
+
# graph.put_object("me", "feed", :message => "Hello, world")
|
|
53
|
+
# writes "Hello, world" to the active user's wall.
|
|
54
|
+
#
|
|
132
55
|
# Most write operations require extended permissions. For example,
|
|
133
56
|
# publishing wall posts requires the "publish_stream" permission. See
|
|
134
57
|
# http://developers.facebook.com/docs/authentication/ for details about
|
|
135
58
|
# extended permissions.
|
|
59
|
+
|
|
60
|
+
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
|
|
61
|
+
graph_call("#{parent_object}/#{connection_name}", args, "post", options)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def delete_object(id, options = {})
|
|
65
|
+
# Deletes the object with the given ID from the graph.
|
|
66
|
+
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Delete requires an access token"}) unless @access_token
|
|
67
|
+
graph_call(id, {}, "delete", options)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Connections
|
|
71
|
+
|
|
72
|
+
def get_connections(id, connection_name, args = {}, options = {})
|
|
73
|
+
# Fetchs the connections for given object.
|
|
74
|
+
result = 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
|
|
136
77
|
|
|
78
|
+
def put_connections(id, connection_name, args = {}, options = {})
|
|
79
|
+
# Posts a certain connection
|
|
137
80
|
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
|
|
138
|
-
graph_call("#{
|
|
81
|
+
graph_call("#{id}/#{connection_name}", args, "post", options)
|
|
139
82
|
end
|
|
83
|
+
|
|
84
|
+
def delete_connections(id, connection_name, args = {}, options = {})
|
|
85
|
+
# Deletes a given connection
|
|
86
|
+
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Delete requires an access token"}) unless @access_token
|
|
87
|
+
graph_call("#{id}/#{connection_name}", args, "delete", options)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Pictures
|
|
91
|
+
# to delete pictures, use delete_object(photo_id)
|
|
92
|
+
# note: you'll need the user_photos permission to actually access photos after uploading them
|
|
140
93
|
|
|
141
|
-
def
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
|
|
145
|
-
|
|
94
|
+
def get_picture(object, args = {}, options = {})
|
|
95
|
+
# Gets a picture object, returning the URL (which Facebook sends as a header)
|
|
96
|
+
result = graph_call("#{object}/picture", args, "get", options.merge(:http_component => :headers))
|
|
97
|
+
result["Location"]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def put_picture(*picture_args)
|
|
101
|
+
# Can be called in multiple ways:
|
|
102
|
+
#
|
|
103
|
+
# put_picture(file, [content_type], ...)
|
|
104
|
+
# put_picture(path_to_file, [content_type], ...)
|
|
105
|
+
#
|
|
106
|
+
# You can pass in uploaded files directly from Rails or Sinatra.
|
|
107
|
+
# (See lib/koala/uploadable_io.rb for supported frameworks)
|
|
108
|
+
#
|
|
109
|
+
# Optional parameters can be added to the end of the argument list:
|
|
110
|
+
# - args: a hash of request parameters (default: {})
|
|
111
|
+
# - target_id: ID of the target where to post the picture (default: "me")
|
|
112
|
+
# - options: a hash of http options passed to the HTTPService module
|
|
146
113
|
#
|
|
147
|
-
#
|
|
148
|
-
#
|
|
114
|
+
# put_picture(file, content_type, {:message => "Message"}, 01234560)
|
|
115
|
+
# put_picture(params[:file], {:message => "Message"})
|
|
116
|
+
|
|
117
|
+
raise KoalaError.new("Wrong number of arguments for put_picture") unless picture_args.size.between?(1, 5)
|
|
118
|
+
|
|
119
|
+
args_offset = picture_args[1].kind_of?(Hash) || picture_args.size == 1 ? 0 : 1
|
|
120
|
+
|
|
121
|
+
args = picture_args[1 + args_offset] || {}
|
|
122
|
+
target_id = picture_args[2 + args_offset] || "me"
|
|
123
|
+
options = picture_args[3 + args_offset] || {}
|
|
124
|
+
|
|
125
|
+
args["source"] = Koala::UploadableIO.new(*picture_args.slice(0, 1 + args_offset))
|
|
126
|
+
|
|
127
|
+
self.put_object(target_id, "photos", args, options)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Wall posts
|
|
131
|
+
# To get wall posts, use get_connections(user, "feed")
|
|
132
|
+
# To delete a wall post, just use delete_object(post_id)
|
|
133
|
+
|
|
134
|
+
def put_wall_post(message, attachment = {}, profile_id = "me", options = {})
|
|
135
|
+
# attachment is a hash describing the wall post
|
|
136
|
+
# (see X for more details)
|
|
137
|
+
# For instance,
|
|
149
138
|
#
|
|
150
|
-
# {"name"
|
|
151
|
-
# "link"
|
|
152
|
-
# "caption"
|
|
153
|
-
# "description"
|
|
154
|
-
# "picture"
|
|
139
|
+
# {"name" => "Link name"
|
|
140
|
+
# "link" => "http://www.example.com/",
|
|
141
|
+
# "caption" => "{*actor*} posted a new review",
|
|
142
|
+
# "description" => "This is a longer description of the attachment",
|
|
143
|
+
# "picture" => "http://www.example.com/thumbnail.jpg"}
|
|
155
144
|
|
|
156
|
-
self.put_object(profile_id, "feed", attachment.merge({:message => message}))
|
|
145
|
+
self.put_object(profile_id, "feed", attachment.merge({:message => message}), options)
|
|
157
146
|
end
|
|
158
|
-
|
|
159
|
-
|
|
147
|
+
|
|
148
|
+
# Comments
|
|
149
|
+
# to delete comments, use delete_object(comment_id)
|
|
150
|
+
# to get comments, use get_connections(object, "likes")
|
|
151
|
+
|
|
152
|
+
def put_comment(object_id, message, options = {})
|
|
160
153
|
# Writes the given comment on the given post.
|
|
161
|
-
self.put_object(object_id, "comments", {:message => message})
|
|
154
|
+
self.put_object(object_id, "comments", {:message => message}, options)
|
|
162
155
|
end
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
|
|
157
|
+
# Likes
|
|
158
|
+
# to get likes, use get_connections(user, "likes")
|
|
159
|
+
|
|
160
|
+
def put_like(object_id, options = {})
|
|
165
161
|
# Likes the given post.
|
|
166
|
-
self.put_object(object_id, "likes")
|
|
162
|
+
self.put_object(object_id, "likes", {}, options)
|
|
167
163
|
end
|
|
168
|
-
|
|
169
|
-
def
|
|
170
|
-
#
|
|
171
|
-
|
|
164
|
+
|
|
165
|
+
def delete_like(object_id, options = {})
|
|
166
|
+
# Unlikes a given object for the logged-in user
|
|
167
|
+
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Unliking requires an access token"}) unless @access_token
|
|
168
|
+
graph_call("#{object_id}/likes", {}, "delete", options)
|
|
172
169
|
end
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
|
|
171
|
+
# Search
|
|
172
|
+
|
|
173
|
+
def search(search_terms, args = {}, options = {})
|
|
174
|
+
args.merge!({:q => search_terms}) unless search_terms.nil?
|
|
175
|
+
result = graph_call("search", args, "get", options)
|
|
177
176
|
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
|
178
|
-
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# API access
|
|
179
180
|
|
|
180
181
|
def graph_call(*args)
|
|
182
|
+
# Direct access to the Facebook API
|
|
183
|
+
# see any of the above methods for example invocations
|
|
181
184
|
response = api(*args) do |response|
|
|
182
185
|
# check for Graph API-specific errors
|
|
183
186
|
if response.is_a?(Hash) && error_details = response["error"]
|
|
@@ -186,7 +189,69 @@ module Koala
|
|
|
186
189
|
end
|
|
187
190
|
|
|
188
191
|
response
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# GraphCollection support
|
|
195
|
+
|
|
196
|
+
def get_page(params)
|
|
197
|
+
# Pages through a set of results stored in a GraphCollection
|
|
198
|
+
# Used for connections and search results
|
|
199
|
+
result = graph_call(*params)
|
|
200
|
+
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
|
189
201
|
end
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class GraphCollection < Array
|
|
207
|
+
#This class is a light wrapper for collections returned
|
|
208
|
+
#from the Graph API.
|
|
209
|
+
#
|
|
210
|
+
#It extends Array to allow direct access to the data colleciton
|
|
211
|
+
#which should allow it to drop in seamlessly.
|
|
212
|
+
#
|
|
213
|
+
#It also allows access to paging information and the
|
|
214
|
+
#ability to get the next/previous page in the collection
|
|
215
|
+
#by calling next_page or previous_page.
|
|
216
|
+
attr_reader :paging
|
|
217
|
+
attr_reader :api
|
|
218
|
+
|
|
219
|
+
def initialize(response, api)
|
|
220
|
+
super response["data"]
|
|
221
|
+
@paging = response["paging"]
|
|
222
|
+
@api = api
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# defines methods for NEXT and PREVIOUS pages
|
|
226
|
+
%w{next previous}.each do |this|
|
|
227
|
+
|
|
228
|
+
# def next_page
|
|
229
|
+
# def previous_page
|
|
230
|
+
define_method "#{this.to_sym}_page" do
|
|
231
|
+
base, args = send("#{this}_page_params")
|
|
232
|
+
base ? @api.get_page([base, args]) : nil
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# def next_page_params
|
|
236
|
+
# def previous_page_params
|
|
237
|
+
define_method "#{this.to_sym}_page_params" do
|
|
238
|
+
return nil unless @paging and @paging[this]
|
|
239
|
+
parse_page_url(@paging[this])
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def parse_page_url(url)
|
|
244
|
+
match = url.match(/.com\/(.*)\?(.*)/)
|
|
245
|
+
base = match[1]
|
|
246
|
+
args = match[2]
|
|
247
|
+
params = CGI.parse(args)
|
|
248
|
+
new_params = {}
|
|
249
|
+
params.each_pair do |key,value|
|
|
250
|
+
new_params[key] = value.join ","
|
|
251
|
+
end
|
|
252
|
+
[base,new_params]
|
|
253
|
+
end
|
|
254
|
+
|
|
190
255
|
end
|
|
191
256
|
end
|
|
192
|
-
end
|
|
257
|
+
end
|