fleakr 0.5.2 → 0.6.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/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
|