fleakr 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +52 -17
- data/lib/fleakr.rb +37 -29
- data/lib/fleakr/api.rb +1 -0
- data/lib/fleakr/api/authentication_request.rb +32 -0
- data/lib/fleakr/api/file_parameter.rb +4 -2
- data/lib/fleakr/api/method_request.rb +11 -12
- data/lib/fleakr/api/parameter_list.rb +75 -48
- data/lib/fleakr/api/upload_request.rb +1 -1
- data/lib/fleakr/api/value_parameter.rb +3 -3
- data/lib/fleakr/objects/authentication_token.rb +4 -0
- data/lib/fleakr/objects/set.rb +24 -0
- data/lib/fleakr/support.rb +2 -1
- data/lib/fleakr/support/object.rb +10 -6
- data/lib/fleakr/support/request.rb +23 -0
- data/lib/fleakr/version.rb +2 -2
- data/test/fixtures/photosets.getInfo.xml +7 -0
- data/test/test_helper.rb +3 -3
- data/test/unit/fleakr/api/authentication_request_test.rb +37 -0
- data/test/unit/fleakr/api/file_parameter_test.rb +0 -5
- data/test/unit/fleakr/api/method_request_test.rb +67 -85
- data/test/unit/fleakr/api/parameter_list_test.rb +116 -97
- data/test/unit/fleakr/api/upload_request_test.rb +5 -15
- data/test/unit/fleakr/objects/authentication_token_test.rb +9 -0
- data/test/unit/fleakr/objects/set_test.rb +30 -1
- data/test/unit/fleakr/support/object_test.rb +12 -6
- data/test/unit/fleakr/support/request_test.rb +42 -0
- data/test/unit/fleakr_test.rb +36 -90
- metadata +7 -4
- data/lib/fleakr/api/parameter.rb +0 -35
- data/test/unit/fleakr/api/parameter_test.rb +0 -34
data/README.rdoc
CHANGED
@@ -12,10 +12,6 @@ A small, yet powerful, gem to interface with Flickr photostreams
|
|
12
12
|
|
13
13
|
=== Bleeding Edge
|
14
14
|
|
15
|
-
sudo gem install reagent-fleakr --source=http://gems.github.com
|
16
|
-
|
17
|
-
Or ...
|
18
|
-
|
19
15
|
$ git clone git://github.com/reagent/fleakr.git
|
20
16
|
$ cd fleakr
|
21
17
|
$ rake gem && sudo gem install pkg/fleakr-<version>.gem
|
@@ -306,8 +302,13 @@ While read-only access to the API gets you quite a bit of data, you'll need to g
|
|
306
302
|
authentication token if you want access to the more powerful features (like uploading your
|
307
303
|
own photos).
|
308
304
|
|
309
|
-
|
310
|
-
|
305
|
+
Depending on how you intend to use the Flickr API, there are 2 methods for performing
|
306
|
+
authenticated calls.
|
307
|
+
|
308
|
+
=== Single User
|
309
|
+
|
310
|
+
You'll need to configure your API key to to use Mobile authentication. If you're viewing your
|
311
|
+
list of keys on the Flickr site, click on the 'Edit key details' link and ensure that:
|
311
312
|
|
312
313
|
1. Your application description and notes are up-to-date
|
313
314
|
1. The value for 'Authentication Type' is set to 'Mobile Application'
|
@@ -315,22 +316,56 @@ to get your auth token. Click on the 'Edit key details' link and ensure that:
|
|
315
316
|
|
316
317
|
Once this is set, you'll see your Authentication URL on the key details page (it will look
|
317
318
|
something like http://www.flickr.com/auth-534525246245). Paste this URL into your browser and
|
318
|
-
confirm access to get your mini-token. Now you're ready to
|
319
|
-
|
320
|
-
require 'rubygems'
|
321
|
-
require 'fleakr'
|
319
|
+
confirm access to get your mini-token. Now you're ready to configure your authentication token:
|
322
320
|
|
323
321
|
Fleakr.api_key = 'ABC123'
|
324
322
|
Fleakr.shared_secret = 'sekrit' # Available with your key details on the Flickr site
|
325
|
-
|
326
|
-
|
323
|
+
|
324
|
+
token = Fleakr.token_from_mini_token('294-585-410')
|
325
|
+
Fleakr.auth_token = token.value
|
326
|
+
|
327
327
|
Fleakr.upload('/path/to/my/photo.jpg')
|
328
|
-
Fleakr.token.value # => "34132412341235-12341234ef34"
|
329
328
|
|
330
|
-
Once you use the mini-token once
|
331
|
-
for future requests,
|
332
|
-
|
333
|
-
|
329
|
+
Once you use the mini-token once it is no longer available. To use the generated auth_token
|
330
|
+
for future requests, you'll need to make sure that you set the value permanently:
|
331
|
+
|
332
|
+
Fleakr.auth_token = '72157622657341094-41241e527f325abb'
|
333
|
+
|
334
|
+
=== Multiple Users
|
335
|
+
|
336
|
+
If you need to have your application access other users photos on their behalf, you'll want to
|
337
|
+
use the Web authentication method. Edit your key details and make sure that:
|
338
|
+
|
339
|
+
1. Your application description and notes are up-to-date
|
340
|
+
1. The value for 'Authentication Type' is set to 'Web Application'
|
341
|
+
1. You configure your callback URL to point to something valid and accessible
|
342
|
+
|
343
|
+
Make sure that your key and secret are set as above. You can then begin the process by requesting
|
344
|
+
that the user authorize access to his Flickr account by redirecting to an authorization URL. I'm
|
345
|
+
assuming Rails conventions here, but this should work with any Ruby web framework:
|
346
|
+
|
347
|
+
redirect_to Fleakr.authorization_url
|
348
|
+
|
349
|
+
By default, we request read permission for access. This doesn't really do much more than what the
|
350
|
+
public API allows, so you can request different permissions when asking for authorization:
|
351
|
+
|
352
|
+
# The values :read, :write, and :delete are supported
|
353
|
+
redirect_to Fleakr.authorization_url(:delete)
|
354
|
+
|
355
|
+
One the user authorizes your application, he will be redirected back to your callback URL with a
|
356
|
+
<tt>frob</tt> parameter as part of the query string. You'll need to exchange this for a token:
|
357
|
+
|
358
|
+
token = Fleakr.token_from_frob(params[:frob])
|
359
|
+
|
360
|
+
The actual authentication token is available by calling <tt>token.value</tt> in the above
|
361
|
+
example. You'll want to store this value somewhere to make future API calls on behalf of this
|
362
|
+
user. To make that process easier, there is a method that you can use that will allow you to
|
363
|
+
automatically scope your requests to the authenticated user:
|
364
|
+
|
365
|
+
user = Fleakr.user_for_token('72157622657341094-41241e527f325abb')
|
366
|
+
|
367
|
+
From there, you can make any of the usual calls available with the API. See
|
368
|
+
Fleakr::Objects::User for more information.
|
334
369
|
|
335
370
|
=== What Went Wrong?
|
336
371
|
|
data/lib/fleakr.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__))
|
2
|
-
require 'rubygems'
|
3
2
|
|
4
3
|
require 'uri'
|
5
4
|
require 'cgi'
|
@@ -19,9 +18,9 @@ require 'digest/md5'
|
|
19
18
|
require 'fileutils'
|
20
19
|
require 'loggable'
|
21
20
|
|
21
|
+
require 'fleakr/support'
|
22
22
|
require 'fleakr/api'
|
23
23
|
require 'fleakr/core_ext'
|
24
|
-
require 'fleakr/support'
|
25
24
|
require 'fleakr/objects'
|
26
25
|
|
27
26
|
# = Fleakr: A small, yet powerful, gem to interface with Flickr photostreams
|
@@ -85,7 +84,7 @@ module Fleakr
|
|
85
84
|
# Generic catch-all exception for any API errors
|
86
85
|
class ApiError < StandardError; end
|
87
86
|
|
88
|
-
mattr_accessor :api_key, :shared_secret, :
|
87
|
+
mattr_accessor :api_key, :shared_secret, :auth_token
|
89
88
|
|
90
89
|
# Find a user based on some unique user data. This method will try to find
|
91
90
|
# the user based on several methods, starting with username and falling back to email and URL
|
@@ -96,11 +95,11 @@ module Fleakr
|
|
96
95
|
# Fleakr.user('user@host.com')
|
97
96
|
# Fleakr.user('http://www.flickr.com/photos/the_decapitator/')
|
98
97
|
#
|
99
|
-
def self.user(user_data)
|
98
|
+
def self.user(user_data, options = {})
|
100
99
|
user = nil
|
101
100
|
[:username, :email, :url].each do |attribute|
|
102
101
|
if user.nil?
|
103
|
-
user = Objects::User.send("find_by_#{attribute}", user_data) rescue nil
|
102
|
+
user = Objects::User.send("find_by_#{attribute}", user_data, options) rescue nil
|
104
103
|
end
|
105
104
|
end
|
106
105
|
user
|
@@ -156,34 +155,43 @@ module Fleakr
|
|
156
155
|
Fleakr::Objects::Contact.find_all(options)
|
157
156
|
end
|
158
157
|
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
158
|
+
# Generate an authorization URL to redirect users to. This defaults to
|
159
|
+
# 'read' permission, but others are available when passed to this method:
|
160
|
+
#
|
161
|
+
# * :read - permission to read private information (default)
|
162
|
+
# * :write - permission to add, edit and delete photo metadata (includes 'read')
|
163
|
+
# * :delete - permission to delete photos (includes 'write' and 'read')
|
164
|
+
#
|
165
|
+
def self.authorization_url(permissions = :read)
|
166
|
+
request = Fleakr::Api::AuthenticationRequest.new(:perms => permissions)
|
167
|
+
request.authorization_url
|
168
|
+
end
|
169
|
+
|
170
|
+
# Exchange a frob for an authentication token. See Fleakr.authorization_url for
|
171
|
+
# more information.
|
172
|
+
#
|
173
|
+
def self.token_from_frob(frob)
|
174
|
+
Fleakr::Objects::AuthenticationToken.from_frob(frob)
|
172
175
|
end
|
173
176
|
|
174
|
-
#
|
177
|
+
# Exchange a mini token for an authentication token.
|
175
178
|
#
|
176
|
-
|
177
|
-
|
178
|
-
def self.#{attribute}=(#{attribute})
|
179
|
-
reset_token
|
180
|
-
@@#{attribute} = #{attribute}
|
181
|
-
end
|
182
|
-
ACCESSOR
|
179
|
+
def self.token_from_mini_token(mini_token)
|
180
|
+
Fleakr::Objects::AuthenticationToken.from_mini_token(mini_token)
|
183
181
|
end
|
184
182
|
|
185
|
-
|
186
|
-
|
183
|
+
# Get the user that this authentication token belongs to. Useful for pulling
|
184
|
+
# relationships scoped to this user.
|
185
|
+
#
|
186
|
+
def self.user_for_token(auth_token)
|
187
|
+
token = Fleakr::Objects::AuthenticationToken.from_auth_token(auth_token)
|
188
|
+
token.user
|
187
189
|
end
|
188
|
-
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
# Alias Fleakr methods as Flickr if possible
|
194
|
+
if defined?(Flickr).nil?
|
195
|
+
Flickr = Fleakr
|
189
196
|
end
|
197
|
+
|
data/lib/fleakr/api.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api # :nodoc:
|
3
|
+
|
4
|
+
# = AuthenticationRequest
|
5
|
+
#
|
6
|
+
# Handles authentication requests for the web authentication method.
|
7
|
+
# Requires that Fleakr.api_key and Fleakr.shared_secret both be set.
|
8
|
+
#
|
9
|
+
class AuthenticationRequest
|
10
|
+
|
11
|
+
include Fleakr::Support::Request
|
12
|
+
|
13
|
+
# The endpoint for the authentication request
|
14
|
+
#
|
15
|
+
def endpoint_url
|
16
|
+
'http://flickr.com/services/auth/'
|
17
|
+
end
|
18
|
+
|
19
|
+
def response # :nodoc:
|
20
|
+
Net::HTTP.get_response(endpoint_uri)
|
21
|
+
end
|
22
|
+
|
23
|
+
# The authorization URL that the user should be redirected to.
|
24
|
+
#
|
25
|
+
def authorization_url
|
26
|
+
@authorization_url ||= response.header['Location']
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -5,19 +5,21 @@ module Fleakr
|
|
5
5
|
#
|
6
6
|
# Parameter class to encapsulate file data sent to the Flickr upload API
|
7
7
|
#
|
8
|
-
class FileParameter
|
8
|
+
class FileParameter
|
9
9
|
|
10
10
|
MIME_TYPES = {
|
11
11
|
'.jpg' => 'image/jpeg',
|
12
12
|
'.png' => 'image/png',
|
13
13
|
'.gif' => 'image/gif'
|
14
14
|
}
|
15
|
+
|
16
|
+
attr_reader :name
|
15
17
|
|
16
18
|
# Create a parameter with name and specified filename
|
17
19
|
#
|
18
20
|
def initialize(name, filename)
|
21
|
+
@name = name
|
19
22
|
@filename = filename
|
20
|
-
super(name, false)
|
21
23
|
end
|
22
24
|
|
23
25
|
# Discover MIME type by file extension using MIME_TYPES constant
|
@@ -7,7 +7,10 @@ module Fleakr
|
|
7
7
|
# UploadRequest class.
|
8
8
|
#
|
9
9
|
class MethodRequest
|
10
|
-
|
10
|
+
|
11
|
+
include Fleakr::Support::Request
|
12
|
+
|
13
|
+
attr_reader :method
|
11
14
|
|
12
15
|
# Makes a request to the Flickr API and returns a valid Response object. If
|
13
16
|
# there are errors on the response it will raise an ApiError exception. See
|
@@ -16,7 +19,7 @@ module Fleakr
|
|
16
19
|
def self.with_response!(method, additional_parameters = {})
|
17
20
|
request = self.new(method, additional_parameters)
|
18
21
|
response = request.send
|
19
|
-
|
22
|
+
|
20
23
|
raise(Fleakr::ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
|
21
24
|
|
22
25
|
response
|
@@ -35,14 +38,17 @@ module Fleakr
|
|
35
38
|
# behavior is to authenticate all calls when we have a token).
|
36
39
|
#
|
37
40
|
def initialize(method, additional_parameters = {})
|
38
|
-
|
39
|
-
|
41
|
+
super(additional_parameters)
|
40
42
|
self.method = method
|
41
43
|
end
|
42
44
|
|
43
45
|
def method=(method) # :nodoc:
|
44
46
|
@method = method.sub(/^(flickr\.)?/, 'flickr.')
|
45
|
-
|
47
|
+
parameters.add_option(:method, @method)
|
48
|
+
end
|
49
|
+
|
50
|
+
def endpoint_url
|
51
|
+
'http://api.flickr.com/services/rest/'
|
46
52
|
end
|
47
53
|
|
48
54
|
def send # :nodoc:
|
@@ -53,13 +59,6 @@ module Fleakr
|
|
53
59
|
Response.new(response_xml)
|
54
60
|
end
|
55
61
|
|
56
|
-
private
|
57
|
-
def endpoint_uri
|
58
|
-
uri = URI.parse('http://api.flickr.com/services/rest/')
|
59
|
-
uri.query = self.parameters.to_query
|
60
|
-
uri
|
61
|
-
end
|
62
|
-
|
63
62
|
end
|
64
63
|
|
65
64
|
end
|
@@ -9,89 +9,116 @@ module Fleakr
|
|
9
9
|
#
|
10
10
|
class ParameterList
|
11
11
|
|
12
|
+
attr_reader :upload_options # :nodoc:
|
13
|
+
|
12
14
|
# Create a new parameter list with optional parameters:
|
13
|
-
# [:authenticate?] Request will automatically be authenticated if Fleakr.token is available
|
14
|
-
# set this to false to force it not to authenticate
|
15
15
|
#
|
16
|
-
#
|
17
|
-
#
|
16
|
+
# list = Fleakr::Api::ParameterList.new(:username => 'reagent')
|
17
|
+
#
|
18
|
+
# You can also disable the sending of the authentication token using
|
19
|
+
# the second parameter:
|
18
20
|
#
|
19
|
-
#
|
20
|
-
# => #<Fleakr::Api::ParameterList:0x1656e6c @list=... >
|
21
|
-
# >> list[:foo]
|
22
|
-
# => #<Fleakr::Api::ValueParameter:0x1656da4 @include_in_signature=true, @name="foo", @value="bar">
|
21
|
+
# list = Fleakr::Api::ParameterList.new({}, false)
|
23
22
|
#
|
24
|
-
def initialize(options = {})
|
25
|
-
|
26
|
-
@
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
options.each {|k,v| self << ValueParameter.new(k.to_s, v) }
|
23
|
+
def initialize(options = {}, send_authentication_token = true)
|
24
|
+
@send_authentication_token = send_authentication_token
|
25
|
+
@options = options
|
26
|
+
@upload_options = {}
|
27
|
+
end
|
31
28
|
|
32
|
-
|
33
|
-
|
29
|
+
# Should we send an authentication token as part of this list of parameters?
|
30
|
+
# By default this is true if the token is available as a global value or if
|
31
|
+
# the :auth_token key/value is part of the initial list. You can override this
|
32
|
+
# in the constructor.
|
33
|
+
#
|
34
|
+
def send_authentication_token?
|
35
|
+
@send_authentication_token && !authentication_token.nil?
|
34
36
|
end
|
35
37
|
|
36
|
-
#
|
38
|
+
# The default options to send as part of the parameter list, defaults to
|
39
|
+
# sending the API key
|
37
40
|
#
|
38
|
-
def
|
39
|
-
|
41
|
+
def default_options
|
42
|
+
{:api_key => Fleakr.api_key}
|
40
43
|
end
|
41
44
|
|
42
|
-
# Should this parameter list be signed?
|
45
|
+
# Should this parameter list be signed? This will be true if Fleakr.shared_secret
|
46
|
+
# is set, false if not.
|
43
47
|
#
|
44
48
|
def sign?
|
45
49
|
!Fleakr.shared_secret.blank?
|
46
50
|
end
|
47
51
|
|
48
|
-
# Should we send the auth_token with the request?
|
49
|
-
#
|
50
|
-
def authenticate?
|
51
|
-
@api_options.has_key?(:authenticate?) ? @api_options[:authenticate?] : !Fleakr.token.blank?
|
52
|
-
end
|
53
|
-
|
54
|
-
# Access an individual parameter by key (symbol or string)
|
55
|
-
#
|
56
|
-
def [](key)
|
57
|
-
list[key.to_s]
|
58
|
-
end
|
59
|
-
|
60
|
-
def boundary # :nodoc:
|
61
|
-
@boundary ||= Digest::MD5.hexdigest(rand.to_s)
|
62
|
-
end
|
63
|
-
|
64
52
|
# Generate the query string representation of this parameter
|
65
53
|
# list - e.g. <tt>foo=bar&blee=baz</tt>
|
66
54
|
#
|
67
55
|
def to_query
|
68
|
-
list.
|
56
|
+
list.map {|element| element.to_query }.join('&')
|
69
57
|
end
|
70
58
|
|
71
59
|
# Generate the form representation of this parameter list including the
|
72
60
|
# boundary
|
73
61
|
#
|
74
62
|
def to_form
|
75
|
-
form = list.
|
76
|
-
form << "--#{
|
63
|
+
form = list.map {|p| "--#{boundary}\r\n#{p.to_form}" }.join
|
64
|
+
form << "--#{boundary}--"
|
77
65
|
|
78
66
|
form
|
79
67
|
end
|
80
68
|
|
69
|
+
# Retrieve the authentication token from either the list of parameters
|
70
|
+
# or the global value (e.g. Fleakr.auth_token)
|
71
|
+
#
|
72
|
+
def authentication_token
|
73
|
+
Fleakr.auth_token.nil? ? @options[:auth_token] : Fleakr.auth_token
|
74
|
+
end
|
75
|
+
|
76
|
+
# Add an option to the list that should be sent with a request.
|
77
|
+
#
|
78
|
+
def add_option(name, value)
|
79
|
+
@options.merge!(name => value)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Add an option that should be sent with an upload request.
|
83
|
+
#
|
84
|
+
def add_upload_option(name, value)
|
85
|
+
@upload_options.merge!(name => value)
|
86
|
+
end
|
87
|
+
|
88
|
+
def options # :nodoc:
|
89
|
+
options = default_options.merge(@options)
|
90
|
+
options.merge!(:auth_token => authentication_token) if send_authentication_token?
|
91
|
+
|
92
|
+
options
|
93
|
+
end
|
94
|
+
|
95
|
+
def boundary # :nodoc:
|
96
|
+
@boundary ||= Digest::MD5.hexdigest(rand.to_s)
|
97
|
+
end
|
98
|
+
|
81
99
|
def signature # :nodoc:
|
82
|
-
|
83
|
-
signature_text =
|
100
|
+
sorted_options = options_without_signature.sort {|a,b| a[0].to_s <=> b[0].to_s }
|
101
|
+
signature_text = sorted_options.map {|o| "#{o[0]}#{o[1]}" }.join
|
84
102
|
|
85
103
|
Digest::MD5.hexdigest("#{Fleakr.shared_secret}#{signature_text}")
|
86
104
|
end
|
87
105
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
106
|
+
def options_without_signature # :nodoc:
|
107
|
+
options.reject {|k,v| k.to_s == 'api_sig'}
|
108
|
+
end
|
109
|
+
|
110
|
+
def options_with_signature # :nodoc:
|
111
|
+
options_without_signature.merge(:api_sig => signature)
|
94
112
|
end
|
113
|
+
|
114
|
+
def list # :nodoc:
|
115
|
+
options_for_list = sign? ? options_with_signature : options_without_signature
|
116
|
+
value_parameters = options_for_list.map {|k,v| ValueParameter.new(k, v) }
|
117
|
+
file_parameters = upload_options.map {|k,v| FileParameter.new(k, v) }
|
118
|
+
|
119
|
+
value_parameters + file_parameters
|
120
|
+
end
|
121
|
+
|
95
122
|
end
|
96
123
|
end
|
97
124
|
end
|