fleakr 0.4.1 → 0.4.2

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.
@@ -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