reagent-fleakr 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.rdoc +115 -20
  2. data/Rakefile +1 -1
  3. data/lib/fleakr.rb +66 -7
  4. data/lib/fleakr/api.rb +7 -0
  5. data/lib/fleakr/api/file_parameter.rb +47 -0
  6. data/lib/fleakr/api/method_request.rb +57 -0
  7. data/lib/fleakr/api/parameter.rb +35 -0
  8. data/lib/fleakr/api/parameter_list.rb +96 -0
  9. data/lib/fleakr/api/response.rb +2 -2
  10. data/lib/fleakr/api/upload_request.rb +64 -0
  11. data/lib/fleakr/api/value_parameter.rb +36 -0
  12. data/lib/fleakr/core_ext.rb +1 -0
  13. data/lib/fleakr/core_ext/hash.rb +22 -0
  14. data/lib/fleakr/objects.rb +9 -0
  15. data/lib/fleakr/objects/authentication_token.rb +43 -0
  16. data/lib/fleakr/objects/contact.rb +5 -5
  17. data/lib/fleakr/objects/error.rb +2 -2
  18. data/lib/fleakr/objects/group.rb +2 -2
  19. data/lib/fleakr/objects/image.rb +7 -7
  20. data/lib/fleakr/objects/photo.rb +69 -5
  21. data/lib/fleakr/objects/search.rb +3 -6
  22. data/lib/fleakr/objects/set.rb +11 -5
  23. data/lib/fleakr/objects/user.rb +14 -26
  24. data/lib/fleakr/support.rb +2 -0
  25. data/lib/fleakr/support/attribute.rb +30 -12
  26. data/lib/fleakr/support/object.rb +20 -4
  27. data/lib/fleakr/version.rb +1 -1
  28. data/test/fixtures/auth.checkToken.xml +8 -0
  29. data/test/fixtures/auth.getFullToken.xml +8 -0
  30. data/test/fixtures/people.getInfo.xml +1 -1
  31. data/test/fixtures/photos.getInfo.xml +20 -0
  32. data/test/test_helper.rb +18 -3
  33. data/test/unit/fleakr/api/file_parameter_test.rb +63 -0
  34. data/test/unit/fleakr/api/method_request_test.rb +103 -0
  35. data/test/unit/fleakr/api/parameter_list_test.rb +161 -0
  36. data/test/unit/fleakr/api/parameter_test.rb +34 -0
  37. data/test/unit/fleakr/api/upload_request_test.rb +133 -0
  38. data/test/unit/fleakr/api/value_parameter_test.rb +41 -0
  39. data/test/unit/fleakr/core_ext/hash_test.rb +32 -0
  40. data/test/unit/fleakr/objects/authentication_token_test.rb +47 -0
  41. data/test/unit/fleakr/objects/image_test.rb +10 -5
  42. data/test/unit/fleakr/objects/photo_test.rb +96 -36
  43. data/test/unit/fleakr/objects/search_test.rb +1 -1
  44. data/test/unit/fleakr/objects/set_test.rb +12 -1
  45. data/test/unit/fleakr/objects/user_test.rb +2 -16
  46. data/test/unit/fleakr/support/attribute_test.rb +82 -24
  47. data/test/unit/fleakr/support/object_test.rb +26 -3
  48. data/test/unit/fleakr_test.rb +65 -6
  49. metadata +27 -4
  50. data/lib/fleakr/api/request.rb +0 -58
  51. data/test/unit/fleakr/api/request_test.rb +0 -93
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  == Description
4
4
 
5
- A teeny tiny gem to interface with Flickr photostreams
5
+ A small, yet powerful, gem to interface with Flickr photostreams
6
6
 
7
7
  == Installation
8
8
 
@@ -22,16 +22,24 @@ Or ...
22
22
 
23
23
  == Usage
24
24
 
25
- Before doing anything, require the library:
25
+ To get started, you'll need to grab an API key from Flickr to at least perform any of
26
+ the non-authenticated, read-only calls. Head on over to the Flickr site to grab one, I'll
27
+ be here when you get back: http://www.flickr.com/services/api/misc.api_keys.html
26
28
 
27
- >> require 'rubygems'
28
- >> require 'fleakr'
29
+ Now that you have your key, you can get things rolling with irb and the fleakr gem:
29
30
 
31
+ $ irb -r rubygems
32
+ >> require 'fleakr'
33
+
30
34
  Then, set your API key (only need to do this once per session):
31
35
 
32
36
  >> Fleakr.api_key = '<your api key here>'
33
-
34
- Find a user by username:
37
+
38
+ === A Brief Tour
39
+
40
+ With just an API key, you have the ability to retrieve a substantial amount of data
41
+ about users, their photosets, photos, contacts, and groups. Let's start by finding a
42
+ user by his username:
35
43
 
36
44
  >> user = Fleakr.user('the decapitator')
37
45
  => #<Fleakr::Objects::User:0x692648 @username="the decapitator", @id="21775151@N06">
@@ -47,13 +55,18 @@ Once you have a user, you can find his associated sets:
47
55
  => [#<Fleakr::Objects::Set:0x671358 @title="The Decapitator", @description="">,
48
56
  #<Fleakr::Objects::Set:0x66d898 @title="londonpaper hijack", ...
49
57
 
58
+ His individual photos:
59
+
60
+ >> user.photos.first
61
+ => #<Fleakr::Objects::Photo:0x161b024 @title="\"Be Fabulous\"" ... >
62
+
50
63
  Or contacts:
51
64
 
52
65
  >> user.contacts.first
53
66
  => #<Fleakr::Objects::User:0x19039bc @username=".schill",
54
67
  @id="12289718@N00", @icon_farm="1", @icon_server="4">
55
68
 
56
- Or groups if you would like:
69
+ Or his groups if you would like:
57
70
 
58
71
  >> user.groups
59
72
  => [#<Fleakr::Objects::Group:0x11f2330 ...,
@@ -65,7 +78,7 @@ Or groups if you would like:
65
78
 
66
79
  Groups also contain photos:
67
80
 
68
- >> u.groups.last.photos.first.title
81
+ >> user.groups.last.photos.first.title
69
82
  => "Welcome To The Machine"
70
83
 
71
84
  When accessing a set, you can also grab all the photos that are in that set:
@@ -77,20 +90,59 @@ When accessing a set, you can also grab all the photos that are in that set:
77
90
  >> user.sets.first.photos.first.title
78
91
  => "Untitled1"
79
92
 
93
+ === Photos
94
+
95
+ Each photo object contains metadata about a collection of images, each representing different
96
+ sizes. Once we have a single photo:
97
+
98
+ >> photo = user.photos.first
99
+ => #<Fleakr::Objects::Photo:0x161b024 @title="\"Be Fabulous\"" ... >
100
+
101
+ We can get information about one of the sizes:
102
+
103
+ >> photo.small
104
+ => #<Fleakr::Objects::Image:0x1768f1c @height="172", @size="Small", @width="240",
105
+ @url="http://farm4.static.flickr.com/3250/2924549350_cbc1804258_m.jpg",
106
+ @page="http://www.flickr.com/photos/the_decapitator/2924549350/sizes/s/">
107
+
108
+ Grab the URL for the image itself:
109
+
110
+ >> photo.small.url
111
+ => "http://farm4.static.flickr.com/3250/2924549350_cbc1804258_m.jpg"
112
+
113
+ Or grab the URL for its page on the Flickr site:
114
+
115
+ >> photo.small.page
116
+ => "http://www.flickr.com/photos/the_decapitator/2924549350/sizes/s/"
117
+
118
+ Other sizes are available (:square, :thumbnail, :small, :medium, :large, :original) and
119
+ are accessed in the same way:
120
+
121
+ >> photo.original.url
122
+ => "http://farm4.static.flickr.com/3250/2924549350_1cf67c2d47_o.jpg"
123
+
124
+ === Saving Images
125
+
80
126
  If a photo interests you, save it down to a directory of your choosing:
81
127
 
82
- >> user.sets.first.photos.first.small.save_to('/tmp')
83
- => #<File:/tmp/2117922283_715587b2cb_m.jpg (closed)>
128
+ >> photo.original.save_to('/tmp')
129
+ => #<File:/tmp/2924549350_1cf67c2d47_o.jpg (closed)>
84
130
 
85
- If you can't decide on a photo and would rather just save the whole set, specify the target directory
86
- and the size of the images you're interested in:
131
+ Similarly, you can save down entire sets. Just specify the target directory and the size
132
+ of the images you're interested in:
87
133
 
88
134
  >> user.sets.first.save_to('/tmp', :square)
89
135
  => [#<Fleakr::Objects::Photo:0x1187a1c @secret="715587b2cb" ...
136
+
137
+ This creates a subdirectory within the target directory based on the set's name and preserves
138
+ the original order of the photos:
139
+
90
140
  >> Dir["/tmp/#{user.sets.first.title}/*.jpg"].map
91
- => ["/tmp/The Decapitator/2117919621_8b2d601bff_s.jpg",
92
- "/tmp/The Decapitator/2117921045_5fb15eff90_s.jpg",
93
- "/tmp/The Decapitator/2117922283_715587b2cb_s.jpg", ...
141
+ => ["/tmp/The Decapitator/01_2117922283_715587b2cb_s.jpg",
142
+ "/tmp/The Decapitator/02_2125604584_9c09348fd6_s.jpg",
143
+ "/tmp/The Decapitator/03_2118696542_8af5763bde_s.jpg", ... ]
144
+
145
+ === Searching
94
146
 
95
147
  If you would prefer to just search photos, you can do that with search text:
96
148
 
@@ -116,13 +168,56 @@ Searches can also be scoped to other entities in the system (namely Users and Gr
116
168
  >> user.search('serpent')
117
169
  => [#<Fleakr::Objects::Photo:0x18a6960 @server_id="41", @id="81370156",
118
170
  @farm_id="1", @title="Clear and Serpent Danger", @secret="013091582a">]
119
-
120
- == TODO
121
171
 
122
- * Implement remaining bits of person, photoset, and photo-releated APIs
172
+ === Authenticated Calls & Uploads
173
+
174
+ While read-only access to the API gets you quite a bit of data, you'll need to generate an
175
+ authentication token if you want access to the more powerful features (like uploading your
176
+ own photos).
177
+
178
+ Assuming you've already applied for a key, go back and make sure you have the right settings
179
+ to get your auth token. Click on the 'Edit key details' link and ensure that:
180
+
181
+ 1. Your application description and notes are up-to-date
182
+ 1. The value for 'Authentication Type' is set to 'Mobile Application'
183
+ 1. The value for 'Mobile Permissions' is set to either 'write' or 'delete'
184
+
185
+ Once this is set, you'll see your Authentication URL on the key details page (it will look
186
+ something like http://www.flickr.com/auth-534525246245). Paste this URL into your browser and
187
+ confirm access to get your mini-token. Now you're ready to make authenticated requests:
188
+
189
+ require 'rubygems'
190
+ require 'fleakr'
191
+
192
+ Fleakr.api_key = 'ABC123'
193
+ Fleakr.shared_secret = 'sekrit' # Available with your key details on the Flickr site
194
+ Fleakr.mini_token = '362-133-214'
195
+
196
+ Fleakr.upload('/path/to/my/photo.jpg')
197
+ Fleakr.token.value # => "34132412341235-12341234ef34"
198
+
199
+ Once you use the mini-token once, it is no longer available. To use the generated auth_token
200
+ for future requests, just set Fleakr.auth_token to the generated value.
201
+
202
+ == Roadmap / TODO
203
+
204
+ === 0.4.x
205
+
206
+ * Allow passing of parameters to file uploads to allow for access control / naming
207
+ * Implement remaining bits of person and photo-related API calls (read-only)
208
+ * Automatically sign all calls (if we have a secret), authenticate all calls (if we have a token)
209
+
210
+ === 0.5.x
211
+
212
+ * Implement asynchronous file upload / replacement w/ ticket checking
123
213
  * Provide a better searching interface
124
- * Lazily load attributes for objects that need to be accessed via secondary API call
125
-
214
+
215
+ === Future
216
+
217
+ * Implement save-able search results (e.g. Fleakr.search('ponies').save_to('/path', :medium))
218
+ * Implement deeper associations for core elements (e.g. tags / etc..)
219
+ * Implement write methods for photos & photosets
220
+
126
221
  == License
127
222
 
128
223
  Copyright (c) 2008 Patrick Reagan (reaganpr@gmail.com)
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ spec = Gem::Specification.new do |s|
12
12
  s.has_rdoc = true
13
13
  s.extra_rdoc_files = %w(README.rdoc)
14
14
  s.rdoc_options = %w(--main README.rdoc)
15
- s.summary = "A teeny tiny gem to interface with Flickr photostreams"
15
+ s.summary = "A small, yet powerful, gem to interface with Flickr photostreams"
16
16
  s.author = 'Patrick Reagan'
17
17
  s.email = 'reaganpr@gmail.com'
18
18
  s.homepage = 'http://sneaq.net'
data/lib/fleakr.rb CHANGED
@@ -6,13 +6,16 @@ require 'net/http'
6
6
  require 'rubygems'
7
7
  require 'hpricot'
8
8
  require 'activesupport'
9
+ require 'md5'
9
10
 
10
- %w(support api objects).each do |path|
11
- full_path = File.expand_path(File.dirname(__FILE__)) + "/fleakr/#{path}"
12
- Dir["#{full_path}/*.rb"].each {|f| require f }
13
- end
11
+ require 'fleakr/api'
12
+ require 'fleakr/core_ext'
13
+ require 'fleakr/support'
14
+ require 'fleakr/objects'
14
15
 
15
- # = Fleakr: A teeny tiny gem to interface with Flickr
16
+ # = Fleakr: A small, yet powerful, gem to interface with Flickr photostreams
17
+ #
18
+ # == Quick Start
16
19
  #
17
20
  # Getting started is easy, just make sure you have a valid API key from Flickr and you can
18
21
  # then start making any non-authenticated request to pull back data for yours and others'
@@ -36,10 +39,42 @@ end
36
39
  # user.groups
37
40
  #
38
41
  # To see what other associations and attributes are available, see the Fleakr::Objects::User class
42
+ #
43
+ # == Authentication
44
+ #
45
+ # If you want to do something more than just retrieve public photos (like upload your own),
46
+ # you'll need to generate an authentication token to use across requests and sessions.
47
+ #
48
+ # Assuming you've already applied for a key, go back and make sure you have the right settings
49
+ # to get your auth token. Click on the 'Edit key details' link and ensure that:
50
+ #
51
+ # 1. Your application description and notes are up-to-date
52
+ # 1. The value for 'Authentication Type' is set to 'Mobile Application'
53
+ # 1. The value for 'Mobile Permissions' is set to either 'write' or 'delete'
54
+ #
55
+ # Once this is set, you'll see your Authentication URL on the key details page (it will look
56
+ # something like http://www.flickr.com/auth-534525246245). Paste this URL into your browser and
57
+ # confirm access to get your mini-token. Now you're ready to make authenticated requests:
58
+ #
59
+ # require 'rubygems'
60
+ # require 'fleakr'
61
+ #
62
+ # Fleakr.api_key = 'ABC123'
63
+ # Fleakr.shared_secret = 'sekrit' # Available with your key details on the Flickr site
64
+ # Fleakr.mini_token = '362-133-214'
65
+ #
66
+ # Fleakr.upload('/path/to/my/photo.jpg')
67
+ # Fleakr.token.value # => "34132412341235-12341234ef34"
68
+ #
69
+ # Once you use the mini-token once, it is no longer available. To use the generated auth_token
70
+ # for future requests, just set Fleakr.auth_token to the generated value.
39
71
  #
40
72
  module Fleakr
41
73
 
42
- mattr_accessor :api_key
74
+ # Generic catch-all exception for any API errors
75
+ class ApiError < StandardError; end
76
+
77
+ mattr_accessor :api_key, :shared_secret, :mini_token, :auth_token
43
78
 
44
79
  # Find a user based on some unique user data. This method will try to find
45
80
  # the user based on username and will fall back to email if that fails. Example:
@@ -51,7 +86,7 @@ module Fleakr
51
86
  def self.user(user_data)
52
87
  begin
53
88
  Objects::User.find_by_username(user_data)
54
- rescue Api::Request::ApiError
89
+ rescue ApiError
55
90
  Objects::User.find_by_email(user_data)
56
91
  end
57
92
  end
@@ -71,4 +106,28 @@ module Fleakr
71
106
  Objects::Search.new(params).results
72
107
  end
73
108
 
109
+ # Upload one or more files to your Flickr account (requires authentication). Simply provide
110
+ # a filename or a pattern to upload one or more files:
111
+ #
112
+ # Fleakr.upload('/path/to/my/mug.jpg')
113
+ # Fleakr.upload('/User/Pictures/Party/*.jpg')
114
+ #
115
+ def self.upload(glob)
116
+ Dir[glob].each {|file| Fleakr::Objects::Photo.upload(file) }
117
+ end
118
+
119
+ # Get the authentication token needed for authenticated requests. Will either use
120
+ # a valid auth_token (if available) or a mini-token to generate the auth_token.
121
+ #
122
+ def self.token
123
+ @token ||= begin
124
+ if !Fleakr.auth_token.nil?
125
+ Fleakr::Objects::AuthenticationToken.from_auth_token(Fleakr.auth_token)
126
+ else
127
+ Fleakr::Objects::AuthenticationToken.from_mini_token(Fleakr.mini_token)
128
+ end
129
+ end
130
+ end
131
+
132
+
74
133
  end
data/lib/fleakr/api.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "fleakr/api/response"
2
+ require "fleakr/api/method_request"
3
+ require "fleakr/api/upload_request"
4
+ require "fleakr/api/parameter_list"
5
+ require "fleakr/api/parameter"
6
+ require "fleakr/api/value_parameter"
7
+ require "fleakr/api/file_parameter"
@@ -0,0 +1,47 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = FileParameter
5
+ #
6
+ # Parameter class to encapsulate file data sent to the Flickr upload API
7
+ #
8
+ class FileParameter < Parameter
9
+
10
+ MIME_TYPES = {
11
+ '.jpg' => 'image/jpeg',
12
+ '.png' => 'image/png',
13
+ '.gif' => 'image/gif'
14
+ }
15
+
16
+ # Create a parameter with name and specified filename
17
+ #
18
+ def initialize(name, filename)
19
+ @filename = filename
20
+ super(name, false)
21
+ end
22
+
23
+ # Discover MIME type by file extension using MIME_TYPES constant
24
+ #
25
+ def mime_type
26
+ MIME_TYPES[File.extname(@filename)]
27
+ end
28
+
29
+ # File data (from @filename) to pass to the Flickr API
30
+ #
31
+ def value
32
+ @value ||= File.read(@filename)
33
+ end
34
+
35
+ # Generate a form representation of this file for upload (as multipart/form-data)
36
+ #
37
+ def to_form
38
+ "Content-Disposition: form-data; name=\"#{self.name}\"; filename=\"#{@filename}\"\r\n" +
39
+ "Content-Type: #{self.mime_type}\r\n" +
40
+ "\r\n" +
41
+ "#{self.value}\r\n"
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,57 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ class MethodRequest
5
+ attr_reader :parameters, :method
6
+
7
+ # Makes a request to the Flickr API and returns a valid Response object. If
8
+ # there are errors on the response it will raise an ApiError exception. See
9
+ # #Fleakr::Api::MethodRequest.new for details about the additional parameters
10
+ #
11
+ def self.with_response!(method, additional_parameters = {})
12
+ request = self.new(method, additional_parameters)
13
+ response = request.send
14
+
15
+ raise(Fleakr::ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
16
+
17
+ response
18
+ end
19
+
20
+ # Create a new request for the specified API method and pass along any additional
21
+ # parameters. The Flickr API uses namespacing for its methods - this is optional
22
+ # when calling this method.
23
+ #
24
+ # This must be called after initializing the library with the required API key
25
+ # see (#Fleakr.api_key=)
26
+ #
27
+ # The <tt>additional_parameters</tt> is a list of parameters to pass directly to
28
+ # the Flickr API call. Exceptions to this are the <tt>:sign?</tt> and
29
+ # <tt>:authenticate?</tt> options that determine if the call should be signed or
30
+ # authenticated.
31
+ #
32
+ def initialize(method, additional_parameters = {})
33
+ @parameters = ParameterList.new(additional_parameters)
34
+
35
+ self.method = method
36
+ end
37
+
38
+ def method=(method) # :nodoc:
39
+ @method = method.sub(/^(flickr\.)?/, 'flickr.')
40
+ @parameters << ValueParameter.new('method', @method)
41
+ end
42
+
43
+ def send # :nodoc:
44
+ Response.new(Net::HTTP.get(endpoint_uri))
45
+ end
46
+
47
+ private
48
+ def endpoint_uri
49
+ uri = URI.parse('http://api.flickr.com/services/rest/')
50
+ uri.query = self.parameters.to_query
51
+ uri
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,35 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = Parameter
5
+ #
6
+ # Base class for other parameters that get passed to the Flickr API - see
7
+ # #FileParameter and #ValueParameter for examples
8
+ #
9
+ class Parameter
10
+
11
+ attr_reader :name
12
+
13
+ # A new named parameter (never used directly)
14
+ #
15
+ def initialize(name, include_in_signature = true)
16
+ @name = name
17
+ @include_in_signature = include_in_signature
18
+ end
19
+
20
+ # Should this parameter be used when generating the signature?
21
+ #
22
+ def include_in_signature?
23
+ (@include_in_signature == true) ? true : false
24
+ end
25
+
26
+ # Used for sorting when generating a signature
27
+ #
28
+ def <=>(other)
29
+ self.name <=> other.name
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end