fleakr 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -169,7 +169,33 @@ Searches can also be scoped to other entities in the system (namely Users and Gr
169
169
  => [#<Fleakr::Objects::Photo:0x18a6960 @server_id="41", @id="81370156",
170
170
  @farm_id="1", @title="Clear and Serpent Danger", @secret="013091582a">]
171
171
 
172
- === Authenticated Calls & Uploads
172
+ === Uploading Files
173
+
174
+ Before you can upload files, you need to be able to make authenticated calls to the Flickr
175
+ API. Skip to the next section (Authenticated Calls) for details on how to make this work.
176
+
177
+ Uploading single files is simple:
178
+
179
+ >> Fleakr.upload('/path/to/image.jpg')
180
+ => [#<Fleakr::Objects::Photo:0x217fb54 @updated="1236133594", @server_id="3266", ...>]
181
+
182
+ Notice that the newly-uploaded image is returned. You can further inspect / modify this as
183
+ necessary. The real magic is in uploading multiple files - the upload method takes a file
184
+ glob:
185
+
186
+ >> Fleakr.upload('/path/to/images/*.jpg')
187
+ => [#<Fleakr::Objects::Photo:0x217faa0 ...>,
188
+ #<Fleakr::Objects::Photo:0x212fb18 ...>,
189
+ #<Fleakr::Objects::Photo:0x20e09c8 ...>]
190
+
191
+ You can also set options on the file(s) that you're uploading:
192
+
193
+ >> Fleakr.upload('/path/to/party/images/*.jpg', :viewable_by => :everyone,
194
+ :title => 'Party Pics')
195
+
196
+ The full list of options can be found in the Fleakr::Objects::Photo documentation.
197
+
198
+ === Authenticated Calls
173
199
 
174
200
  While read-only access to the API gets you quite a bit of data, you'll need to generate an
175
201
  authentication token if you want access to the more powerful features (like uploading your
@@ -197,7 +223,9 @@ confirm access to get your mini-token. Now you're ready to make authenticated re
197
223
  Fleakr.token.value # => "34132412341235-12341234ef34"
198
224
 
199
225
  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.
226
+ for future requests, just set Fleakr.auth_token to the generated value. Similarly, if you have
227
+ an authenticated frob from Flickr (using authentication for desktop applications, for example)
228
+ you can also set <tt>Fleakr.frob</tt> to the frob value returned from the API.
201
229
 
202
230
  === What Went Wrong?
203
231
 
@@ -223,20 +251,19 @@ API requests.
223
251
 
224
252
  === 0.4.x
225
253
 
226
- * Allow passing of parameters to file uploads to allow for access control / naming
227
254
  * Implement remaining bits of person and photo-related API calls (read-only)
228
- * Automatically sign all calls (if we have a secret), authenticate all calls (if we have a token)
229
255
 
230
256
  === 0.5.x
231
257
 
232
258
  * Implement asynchronous file upload / replacement w/ ticket checking
233
- * Provide a better searching interface
259
+ * Provide a better searching interface with ruby-like option syntax
234
260
 
235
261
  === Future
236
262
 
237
263
  * Implement save-able search results (e.g. Fleakr.search('ponies').save_to('/path', :medium))
238
264
  * Implement deeper associations for core elements (e.g. tags / etc..)
239
265
  * Implement write methods for photos & photosets
266
+ * Implement flickr.places.* portion of API
240
267
 
241
268
  == License
242
269
 
data/Rakefile CHANGED
@@ -19,7 +19,7 @@ spec = Gem::Specification.new do |s|
19
19
  s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,test}/**/*")
20
20
 
21
21
  s.add_dependency('hpricot', '~> 0.6.0')
22
- s.add_dependency('activesupport', '~> 2.2.0')
22
+ s.add_dependency('activesupport', '~> 2.0')
23
23
  s.add_dependency('loggable', '~> 0.2.0')
24
24
  end
25
25
 
@@ -5,7 +5,15 @@ require 'uri'
5
5
  require 'cgi'
6
6
  require 'net/http'
7
7
  require 'hpricot'
8
- require 'activesupport'
8
+
9
+ # Require only what we need from ActiveSupport
10
+ require 'active_support/core_ext/array'
11
+ require 'active_support/core_ext/module'
12
+ require 'active_support/core_ext/blank'
13
+ require 'active_support/core_ext/time'
14
+ require 'active_support/inflector'
15
+ require 'active_support/core_ext/string'
16
+
9
17
  require 'md5'
10
18
  require 'loggable'
11
19
 
@@ -75,7 +83,7 @@ module Fleakr
75
83
  # Generic catch-all exception for any API errors
76
84
  class ApiError < StandardError; end
77
85
 
78
- mattr_accessor :api_key, :shared_secret, :mini_token, :auth_token
86
+ mattr_accessor :api_key, :shared_secret, :mini_token, :auth_token, :frob
79
87
 
80
88
  # Find a user based on some unique user data. This method will try to find
81
89
  # the user based on username and will fall back to email if that fails. Example:
@@ -113,8 +121,12 @@ module Fleakr
113
121
  # Fleakr.upload('/path/to/my/mug.jpg')
114
122
  # Fleakr.upload('/User/Pictures/Party/*.jpg')
115
123
  #
116
- def self.upload(glob)
117
- Dir[glob].each {|file| Fleakr::Objects::Photo.upload(file) }
124
+ # Additionally, options can be supplied as part of the upload that will apply to all files
125
+ # that are matched by the pattern passed to <tt>glob</tt>. For a full list, see
126
+ # Fleakr::Objects::Photo.
127
+ #
128
+ def self.upload(glob, options = {})
129
+ Dir[glob].map {|file| Fleakr::Objects::Photo.upload(file, options) }
118
130
  end
119
131
 
120
132
  # Get the authentication token needed for authenticated requests. Will either use
@@ -122,13 +134,29 @@ module Fleakr
122
134
  #
123
135
  def self.token
124
136
  @token ||= begin
125
- if !Fleakr.auth_token.nil?
137
+ if Fleakr.auth_token
126
138
  Fleakr::Objects::AuthenticationToken.from_auth_token(Fleakr.auth_token)
127
- else
139
+ elsif Fleakr.frob
140
+ Fleakr::Objects::AuthenticationToken.from_frob(Fleakr.frob)
141
+ elsif Fleakr.mini_token
128
142
  Fleakr::Objects::AuthenticationToken.from_mini_token(Fleakr.mini_token)
129
143
  end
130
144
  end
131
145
  end
146
+
147
+ # Reset the cached token whenever setting a new value for the mini_token, auth_token, or frob
148
+ #
149
+ [:mini_token, :auth_token, :frob].each do |attribute|
150
+ class_eval <<-ACCESSOR
151
+ def self.#{attribute}=(#{attribute})
152
+ reset_token
153
+ @@#{attribute} = #{attribute}
154
+ end
155
+ ACCESSOR
156
+ end
132
157
 
158
+ def self.reset_token # :nodoc: #
159
+ @token = nil
160
+ end
133
161
 
134
162
  end
@@ -1,5 +1,6 @@
1
1
  require "fleakr/api/response"
2
2
  require "fleakr/api/method_request"
3
+ require "fleakr/api/option"
3
4
  require "fleakr/api/upload_request"
4
5
  require "fleakr/api/parameter_list"
5
6
  require "fleakr/api/parameter"
@@ -1,12 +1,17 @@
1
1
  module Fleakr
2
2
  module Api # :nodoc:
3
3
 
4
+ # = MethodRequest
5
+ #
6
+ # Handles all API requests that are non-upload related. For upload requests see the
7
+ # UploadRequest class.
8
+ #
4
9
  class MethodRequest
5
10
  attr_reader :parameters, :method
6
11
 
7
12
  # Makes a request to the Flickr API and returns a valid Response object. If
8
13
  # there are errors on the response it will raise an ApiError exception. See
9
- # #Fleakr::Api::MethodRequest.new for details about the additional parameters
14
+ # MethodRequest#new for details about the additional parameters
10
15
  #
11
16
  def self.with_response!(method, additional_parameters = {})
12
17
  request = self.new(method, additional_parameters)
@@ -25,9 +30,9 @@ module Fleakr
25
30
  # see (#Fleakr.api_key=)
26
31
  #
27
32
  # 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.
33
+ # the Flickr API call. The exception to this is the <tt>:authenticate?</tt> option
34
+ # that will force the call to not be authenticated if it is set to false (The default
35
+ # behavior is to authenticate all calls when we have a token).
31
36
  #
32
37
  def initialize(method, additional_parameters = {})
33
38
  @parameters = ParameterList.new(additional_parameters)
@@ -0,0 +1,175 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = Option
5
+ #
6
+ # Top-level class for creating specific option instances based on type
7
+ #
8
+ class Option
9
+
10
+ MAPPING = {
11
+ :tags => 'TagOption',
12
+ :viewable_by => 'ViewOption',
13
+ :level => 'LevelOption',
14
+ :type => 'TypeOption',
15
+ :hide? => 'HiddenOption'
16
+ }
17
+
18
+ # Initialize a new option for the specified type and value
19
+ #
20
+ def self.for(type, value)
21
+ class_for(type).new(type, value)
22
+ end
23
+
24
+ def self.class_for(type) # :nodoc:
25
+ class_name = MAPPING[type] || 'SimpleOption'
26
+ "Fleakr::Api::#{class_name}".constantize
27
+ end
28
+
29
+ end
30
+
31
+ # = SimpleOption
32
+ #
33
+ # Simple name / value option pair
34
+ #
35
+ class SimpleOption
36
+
37
+ attr_reader :type, :value
38
+
39
+ # Create an option of the specified type and value
40
+ #
41
+ def initialize(type, value)
42
+ @type = type
43
+ @value = value
44
+ end
45
+
46
+ # Generate hash representation of this option
47
+ #
48
+ def to_hash
49
+ {type => value}
50
+ end
51
+
52
+ end
53
+
54
+ # = TagOption
55
+ #
56
+ # Represents values for tags
57
+ #
58
+ class TagOption < SimpleOption
59
+
60
+ # Tag with specified values. Value passed will be converted to an array if it isn't
61
+ # already
62
+ #
63
+ def initialize(type, value)
64
+ super type, value
65
+ @value = Array(self.value)
66
+ end
67
+
68
+ # Hash representation of tag values (separated by spaces). Handles multi-word tags
69
+ # by enclosing each tag in double quotes.
70
+ #
71
+ def to_hash
72
+ tags = value.map {|tag| "\"#{tag}\"" }
73
+ {type => tags.join(' ')}
74
+ end
75
+
76
+ end
77
+
78
+ # = ViewOption
79
+ #
80
+ # Specify who is able to view the photo.
81
+ #
82
+ class ViewOption < SimpleOption
83
+
84
+ # Specify who this is viewable by (e.g. everyone / friends / family).
85
+ #
86
+ def initialize(type, value)
87
+ super type, Array(value)
88
+ end
89
+
90
+ # Is this publicly viewable? (i.e. :everyone)
91
+ #
92
+ def public?
93
+ value == [:everyone]
94
+ end
95
+
96
+ # Is this viewable by friends? (i.e. :friends)
97
+ #
98
+ def friends?
99
+ value.include?(:friends)
100
+ end
101
+
102
+ # Is this viewable by family? (i.e. :family)
103
+ #
104
+ def family?
105
+ value.include?(:family)
106
+ end
107
+
108
+ # Hash representation of photo permissions
109
+ #
110
+ def to_hash
111
+ {:is_public => public?.to_i, :is_friend => friends?.to_i, :is_family => family?.to_i}
112
+ end
113
+
114
+ end
115
+
116
+ # = LevelOption
117
+ #
118
+ # Specify the "safety level" of this photo (e.g. safe / moderate / restricted)
119
+ #
120
+ class LevelOption < SimpleOption
121
+
122
+ def value # :nodoc:
123
+ case @value
124
+ when :safe: 1
125
+ when :moderate: 2
126
+ when :restricted: 3
127
+ end
128
+ end
129
+
130
+ # Hash representation of the safety_level for this photo
131
+ #
132
+ def to_hash
133
+ {:safety_level => value}
134
+ end
135
+
136
+ end
137
+
138
+ # = TypeOption
139
+ #
140
+ # Specify the type of this photo (e.g. photo / screenshot / other)
141
+ #
142
+ class TypeOption < SimpleOption
143
+
144
+ def value # :nodoc:
145
+ case @value
146
+ when :photo: 1
147
+ when :screenshot: 2
148
+ when :other: 3
149
+ end
150
+ end
151
+
152
+ # Hash representation of this type
153
+ #
154
+ def to_hash
155
+ {:content_type => value}
156
+ end
157
+
158
+ end
159
+
160
+ # = HiddenOption
161
+ #
162
+ # Specify whether this photo should be hidden from search
163
+ #
164
+ class HiddenOption < SimpleOption
165
+
166
+ # Hash representation of whether to hide this photo
167
+ #
168
+ def to_hash
169
+ {:hidden => (value ? 2 : 1)}
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+ end
@@ -10,8 +10,8 @@ module Fleakr
10
10
  class ParameterList
11
11
 
12
12
  # Create a new parameter list with optional parameters:
13
- # [:sign?] Will these parameters be used to sign the request?
14
- # [:authenticate?] Will the request need to be authenticated?
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
16
  # Any additional name / value pairs will be created as individual
17
17
  # ValueParameters as part of the list. Example:
@@ -22,7 +22,8 @@ module Fleakr
22
22
  # => #<Fleakr::Api::ValueParameter:0x1656da4 @include_in_signature=true, @name="foo", @value="bar">
23
23
  #
24
24
  def initialize(options = {})
25
- @api_options = options.extract!(:sign?, :authenticate?)
25
+ # TODO: need to find a way to move the unexpected behavior in Fleakr.token elsewhere
26
+ @api_options = options.extract!(:authenticate?)
26
27
 
27
28
  @list = Hash.new
28
29
 
@@ -41,13 +42,13 @@ module Fleakr
41
42
  # Should this parameter list be signed?
42
43
  #
43
44
  def sign?
44
- (@api_options[:sign?] == true || authenticate?) ? true : false
45
+ !Fleakr.shared_secret.blank?
45
46
  end
46
47
 
47
48
  # Should we send the auth_token with the request?
48
49
  #
49
50
  def authenticate?
50
- (@api_options[:authenticate?] == true) ? true : false
51
+ @api_options.has_key?(:authenticate?) ? @api_options[:authenticate?] : !Fleakr.token.blank?
51
52
  end
52
53
 
53
54
  # Access an individual parameter by key (symbol or string)
@@ -64,7 +65,7 @@ module Fleakr
64
65
  # list - e.g. <tt>foo=bar&blee=baz</tt>
65
66
  #
66
67
  def to_query
67
- list.values.map(&:to_query).join('&')
68
+ list.values.map {|element| element.to_query }.join('&')
68
69
  end
69
70
 
70
71
  # Generate the form representation of this parameter list including the
@@ -19,8 +19,8 @@ module Fleakr
19
19
  # a Fleakr::ApiError with the reason for the error. See UploadRequest#new for more
20
20
  # details.
21
21
  #
22
- def self.with_response!(filename, options = {})
23
- request = self.new(filename, options)
22
+ def self.with_response!(filename, type = :create, options = {})
23
+ request = self.new(filename, type, options)
24
24
  response = request.send
25
25
 
26
26
  raise(Fleakr::ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
@@ -28,21 +28,27 @@ module Fleakr
28
28
  response
29
29
  end
30
30
 
31
- # Create a new UploadRequest with the specified filename and options:
31
+ # Create a new UploadRequest with the specified filename, type, and options. Type
32
+ # is one of <tt>:create</tt> or <tt>:update</tt> to specify whether we are saving a new
33
+ # image or replacing an existing one.
32
34
  #
33
- # [:type] Valid values are :create and :update and are used when uploading new
34
- # photos or replacing existing ones
35
+ # For a list of available options, see the documentation in Fleakr::Objects::Photo
35
36
  #
36
- def initialize(filename, options = {})
37
- type_options = options.extract!(:type)
38
- options.merge!(:authenticate? => true)
37
+ def initialize(filename, type = :create, options = {})
38
+ @type = type
39
+ @options = options
39
40
 
40
- @type = type_options[:type] || :create
41
-
42
- @parameters = ParameterList.new(options)
41
+ @parameters = ParameterList.new(upload_options)
43
42
  @parameters << FileParameter.new('photo', filename)
44
43
  end
45
44
 
45
+ # A list of upload options for this upload request (see Fleakr::Api::Option)
46
+ #
47
+ def upload_options
48
+ option_list = @options.map {|key, value| Option.for(key, value) }
49
+ option_list.inject({}) {|hash, option| hash.merge(option.to_hash)}
50
+ end
51
+
46
52
  def headers # :nodoc:
47
53
  {'Content-Type' => "multipart/form-data; boundary=#{self.parameters.boundary}"}
48
54
  end