slaskis-fleakr 0.5.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 +350 -0
- data/Rakefile +41 -0
- data/lib/fleakr.rb +164 -0
- data/lib/fleakr/api.rb +8 -0
- data/lib/fleakr/api/file_parameter.rb +47 -0
- data/lib/fleakr/api/method_request.rb +66 -0
- data/lib/fleakr/api/option.rb +175 -0
- data/lib/fleakr/api/parameter.rb +35 -0
- data/lib/fleakr/api/parameter_list.rb +97 -0
- data/lib/fleakr/api/response.rb +35 -0
- data/lib/fleakr/api/upload_request.rb +75 -0
- data/lib/fleakr/api/value_parameter.rb +36 -0
- data/lib/fleakr/core_ext.rb +3 -0
- data/lib/fleakr/core_ext/false_class.rb +7 -0
- data/lib/fleakr/core_ext/hash.rb +22 -0
- data/lib/fleakr/core_ext/true_class.rb +7 -0
- data/lib/fleakr/objects.rb +13 -0
- data/lib/fleakr/objects/authentication_token.rb +60 -0
- data/lib/fleakr/objects/comment.rb +49 -0
- data/lib/fleakr/objects/contact.rb +31 -0
- data/lib/fleakr/objects/error.rb +22 -0
- data/lib/fleakr/objects/group.rb +36 -0
- data/lib/fleakr/objects/image.rb +50 -0
- data/lib/fleakr/objects/photo.rb +147 -0
- data/lib/fleakr/objects/photo_context.rb +49 -0
- data/lib/fleakr/objects/search.rb +30 -0
- data/lib/fleakr/objects/set.rb +51 -0
- data/lib/fleakr/objects/tag.rb +56 -0
- data/lib/fleakr/objects/user.rb +95 -0
- data/lib/fleakr/support.rb +2 -0
- data/lib/fleakr/support/attribute.rb +46 -0
- data/lib/fleakr/support/object.rb +112 -0
- data/lib/fleakr/version.rb +13 -0
- data/test/fixtures/auth.checkToken.xml +8 -0
- data/test/fixtures/auth.getFullToken.xml +8 -0
- data/test/fixtures/auth.getToken.xml +8 -0
- data/test/fixtures/contacts.getPublicList.xml +7 -0
- data/test/fixtures/groups.pools.getPhotos.xml +7 -0
- data/test/fixtures/people.findByEmail.xml +6 -0
- data/test/fixtures/people.findByUsername.xml +6 -0
- data/test/fixtures/people.getInfo.xml +18 -0
- data/test/fixtures/people.getPublicGroups.xml +7 -0
- data/test/fixtures/people.getPublicPhotos.xml +7 -0
- data/test/fixtures/photos.comments.getList.xml +7 -0
- data/test/fixtures/photos.getContext.xml +6 -0
- data/test/fixtures/photos.getInfo.xml +20 -0
- data/test/fixtures/photos.getSizes.xml +10 -0
- data/test/fixtures/photos.search.xml +7 -0
- data/test/fixtures/photosets.comments.getList.xml +7 -0
- data/test/fixtures/photosets.getList.xml +13 -0
- data/test/fixtures/photosets.getPhotos.xml +7 -0
- data/test/fixtures/tags.getListPhoto.xml +9 -0
- data/test/fixtures/tags.getListUser.xml +10 -0
- data/test/fixtures/tags.getRelated.xml +9 -0
- data/test/test_helper.rb +141 -0
- data/test/unit/fleakr/api/file_parameter_test.rb +63 -0
- data/test/unit/fleakr/api/method_request_test.rb +94 -0
- data/test/unit/fleakr/api/option_test.rb +179 -0
- data/test/unit/fleakr/api/parameter_list_test.rb +176 -0
- data/test/unit/fleakr/api/parameter_test.rb +34 -0
- data/test/unit/fleakr/api/response_test.rb +49 -0
- data/test/unit/fleakr/api/upload_request_test.rb +149 -0
- data/test/unit/fleakr/api/value_parameter_test.rb +41 -0
- data/test/unit/fleakr/core_ext/false_class_test.rb +13 -0
- data/test/unit/fleakr/core_ext/hash_test.rb +32 -0
- data/test/unit/fleakr/core_ext/true_class_test.rb +13 -0
- data/test/unit/fleakr/objects/authentication_token_test.rb +61 -0
- data/test/unit/fleakr/objects/comment_test.rb +66 -0
- data/test/unit/fleakr/objects/contact_test.rb +61 -0
- data/test/unit/fleakr/objects/error_test.rb +21 -0
- data/test/unit/fleakr/objects/group_test.rb +46 -0
- data/test/unit/fleakr/objects/image_test.rb +81 -0
- data/test/unit/fleakr/objects/photo_context_test.rb +80 -0
- data/test/unit/fleakr/objects/photo_test.rb +246 -0
- data/test/unit/fleakr/objects/search_test.rb +74 -0
- data/test/unit/fleakr/objects/set_test.rb +82 -0
- data/test/unit/fleakr/objects/tag_test.rb +98 -0
- data/test/unit/fleakr/objects/user_test.rb +91 -0
- data/test/unit/fleakr/support/attribute_test.rb +126 -0
- data/test/unit/fleakr/support/object_test.rb +129 -0
- data/test/unit/fleakr_test.rb +171 -0
- metadata +175 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api # :nodoc:
|
3
|
+
|
4
|
+
# = UploadRequest
|
5
|
+
#
|
6
|
+
# This implements the upload functionality of the Flickr API which is needed
|
7
|
+
# to create new photos and replace the photo content of existing photos
|
8
|
+
#
|
9
|
+
class UploadRequest
|
10
|
+
|
11
|
+
ENDPOINT_URIS = {
|
12
|
+
:create => 'http://api.flickr.com/services/upload/',
|
13
|
+
:update => 'http://api.flickr.com/services/replace/'
|
14
|
+
}
|
15
|
+
|
16
|
+
attr_reader :parameters, :type
|
17
|
+
|
18
|
+
# Send a request and return a Response object. If an API error occurs, this raises
|
19
|
+
# a Fleakr::ApiError with the reason for the error. See UploadRequest#new for more
|
20
|
+
# details.
|
21
|
+
#
|
22
|
+
def self.with_response!(filename, type = :create, options = {})
|
23
|
+
request = self.new(filename, type, options)
|
24
|
+
response = request.send
|
25
|
+
|
26
|
+
raise(Fleakr::ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
|
27
|
+
|
28
|
+
response
|
29
|
+
end
|
30
|
+
|
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.
|
34
|
+
#
|
35
|
+
# For a list of available options, see the documentation in Fleakr::Objects::Photo
|
36
|
+
#
|
37
|
+
def initialize(filename, type = :create, options = {})
|
38
|
+
@type = type
|
39
|
+
@options = options
|
40
|
+
|
41
|
+
@parameters = ParameterList.new(upload_options)
|
42
|
+
@parameters << FileParameter.new('photo', filename)
|
43
|
+
end
|
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
|
+
|
52
|
+
def headers # :nodoc:
|
53
|
+
{'Content-Type' => "multipart/form-data; boundary=#{self.parameters.boundary}"}
|
54
|
+
end
|
55
|
+
|
56
|
+
def send # :nodoc:
|
57
|
+
response = Net::HTTP.start(endpoint_uri.host, endpoint_uri.port) do |http|
|
58
|
+
logger.info("Sending upload request to: #{endpoint_uri}")
|
59
|
+
logger.debug("Request data:\n#{self.parameters.to_form}")
|
60
|
+
logger.debug("Request headers:\n#{self.headers.inspect}")
|
61
|
+
|
62
|
+
http.post(endpoint_uri.path, self.parameters.to_form, self.headers)
|
63
|
+
end
|
64
|
+
logger.debug("Response data:\n#{response.body}")
|
65
|
+
Response.new(response.body)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def endpoint_uri
|
70
|
+
@endpoint_uri ||= URI.parse(ENDPOINT_URIS[self.type])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api # :nodoc:
|
3
|
+
|
4
|
+
# = ValueParameter
|
5
|
+
#
|
6
|
+
# A simple name / value parameter for use in API calls
|
7
|
+
#
|
8
|
+
class ValueParameter < Parameter
|
9
|
+
|
10
|
+
attr_reader :value
|
11
|
+
|
12
|
+
# Create a new parameter with the specified name / value pair.
|
13
|
+
#
|
14
|
+
def initialize(name, value, include_in_signature = true)
|
15
|
+
@value = value
|
16
|
+
super(name, include_in_signature)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Generate the query string representation of this parameter.
|
20
|
+
#
|
21
|
+
def to_query
|
22
|
+
"#{self.name}=#{CGI.escape(self.value.to_s)}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Generate the form representation of this parameter.
|
26
|
+
#
|
27
|
+
def to_form
|
28
|
+
"Content-Disposition: form-data; name=\"#{self.name}\"\r\n" +
|
29
|
+
"\r\n" +
|
30
|
+
"#{self.value}\r\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
# Extract the matching keys from the source hash and return
|
4
|
+
# a new hash with those keys:
|
5
|
+
#
|
6
|
+
# >> h = {:a => 'b', :c => 'd'}
|
7
|
+
# => {:a=>"b", :c=>"d"}
|
8
|
+
# >> h.extract!(:a)
|
9
|
+
# => {:a=>"b"}
|
10
|
+
# >> h
|
11
|
+
# => {:c=>"d"}
|
12
|
+
#
|
13
|
+
def extract!(*keys)
|
14
|
+
value = {}
|
15
|
+
|
16
|
+
keys.each {|k| value.merge!({k => self[k]}) if self.has_key?(k) }
|
17
|
+
keys.each {|k| delete(k) }
|
18
|
+
|
19
|
+
value
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'fleakr/objects/authentication_token'
|
2
|
+
require 'fleakr/objects/collection'
|
3
|
+
require 'fleakr/objects/contact'
|
4
|
+
require 'fleakr/objects/error'
|
5
|
+
require 'fleakr/objects/group'
|
6
|
+
require 'fleakr/objects/image'
|
7
|
+
require 'fleakr/objects/photo_context'
|
8
|
+
require 'fleakr/objects/photo'
|
9
|
+
require 'fleakr/objects/comment'
|
10
|
+
require 'fleakr/objects/tag'
|
11
|
+
require 'fleakr/objects/search'
|
12
|
+
require 'fleakr/objects/set'
|
13
|
+
require 'fleakr/objects/user'
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = AuthenticationToken
|
5
|
+
#
|
6
|
+
# This class represents an authentication token used for API calls that
|
7
|
+
# require authentication before they can be used
|
8
|
+
#
|
9
|
+
# == Attributes
|
10
|
+
#
|
11
|
+
# [value] The token value that is used in subsequent API calls
|
12
|
+
# [permissions] The permissions granted to this application (read / write / delete)
|
13
|
+
#
|
14
|
+
class AuthenticationToken
|
15
|
+
|
16
|
+
include Fleakr::Support::Object
|
17
|
+
|
18
|
+
flickr_attribute :value, :from => 'auth/token'
|
19
|
+
flickr_attribute :permissions, :from => 'auth/perms'
|
20
|
+
flickr_attribute :user_id, :from => 'auth/user@nsid'
|
21
|
+
flickr_attribute :user_name, :from => 'auth/user@username'
|
22
|
+
flickr_attribute :full_name, :from => 'auth/user@fullname'
|
23
|
+
|
24
|
+
# Retrieve a full authentication token from the supplied mini-token (e.g. 123-456-789)
|
25
|
+
#
|
26
|
+
def self.from_mini_token(mini_token)
|
27
|
+
from :mini_token, mini_token
|
28
|
+
end
|
29
|
+
|
30
|
+
# Retrieve a full authentication token from the supplied auth_token string
|
31
|
+
# (e.g. 45-76598454353455)
|
32
|
+
#
|
33
|
+
def self.from_auth_token(auth_token)
|
34
|
+
from :auth_token, auth_token
|
35
|
+
end
|
36
|
+
|
37
|
+
# Retrieve a full authentication token from the supplied frob
|
38
|
+
def self.from_frob(frob)
|
39
|
+
from :frob, frob
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.from(thing, value) # :nodoc:
|
43
|
+
api_methods = {
|
44
|
+
:mini_token => 'getFullToken',
|
45
|
+
:auth_token => 'checkToken',
|
46
|
+
:frob => 'getToken'
|
47
|
+
}
|
48
|
+
|
49
|
+
method = "auth.#{api_methods[thing]}"
|
50
|
+
|
51
|
+
parameters = {thing => value, :authenticate? => false}
|
52
|
+
response = Fleakr::Api::MethodRequest.with_response!(method, parameters)
|
53
|
+
|
54
|
+
self.new(response.body)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = Comment
|
5
|
+
#
|
6
|
+
# This class represents a comment that can be associated with a single photo or an
|
7
|
+
# entire photoset.
|
8
|
+
#
|
9
|
+
# == Attributes
|
10
|
+
#
|
11
|
+
# [id] The unique identifier for this comment
|
12
|
+
# [url] The direct URL / permalink to reference this comment
|
13
|
+
# [body] The comment itself - also available with <tt>to_s</tt>
|
14
|
+
#
|
15
|
+
class Comment
|
16
|
+
|
17
|
+
include Fleakr::Support::Object
|
18
|
+
|
19
|
+
find_all :by_photo_id, :call => 'photos.comments.getList', :path => 'comments/comment'
|
20
|
+
find_all :by_set_id, :using => :photoset_id, :call => 'photosets.comments.getList', :path => 'comments/comment'
|
21
|
+
|
22
|
+
flickr_attribute :id
|
23
|
+
flickr_attribute :author_id, :from => '@author'
|
24
|
+
flickr_attribute :created, :from => '@datecreate'
|
25
|
+
flickr_attribute :url, :from => '@permalink'
|
26
|
+
flickr_attribute :body, :from => '.'
|
27
|
+
|
28
|
+
# The user who supplied the comment. See Fleakr::Objects::User for more information
|
29
|
+
#
|
30
|
+
def author
|
31
|
+
@author ||= User.find_by_id(author_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
# When was this comment created?
|
35
|
+
#
|
36
|
+
def created_at
|
37
|
+
Time.at(created.to_i)
|
38
|
+
end
|
39
|
+
|
40
|
+
# The contents of the comment - also available as <tt>body</tt>
|
41
|
+
#
|
42
|
+
def to_s
|
43
|
+
body
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
class Contact # :nodoc:
|
4
|
+
|
5
|
+
include Fleakr::Support::Object
|
6
|
+
|
7
|
+
flickr_attribute :id, :from => '@nsid'
|
8
|
+
flickr_attribute :username
|
9
|
+
flickr_attribute :icon_server, :from => '@iconserver'
|
10
|
+
flickr_attribute :icon_farm, :from => '@iconfarm'
|
11
|
+
|
12
|
+
# Retrieve a list of contacts for the specified user ID and return an initialized
|
13
|
+
# collection of #User objects
|
14
|
+
def self.find_all_by_user_id(user_id)
|
15
|
+
response = Fleakr::Api::MethodRequest.with_response!('contacts.getPublicList', :user_id => user_id)
|
16
|
+
(response.body/'contacts/contact').map {|c| Contact.new(c).to_user }
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_user
|
20
|
+
user = User.new
|
21
|
+
self.class.attributes.each do |attribute|
|
22
|
+
attribute_name = attribute.name
|
23
|
+
user.send("#{attribute.name}=".to_sym, self.send(attribute.name))
|
24
|
+
end
|
25
|
+
|
26
|
+
user
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
# = Error
|
4
|
+
#
|
5
|
+
# == Accessors
|
6
|
+
#
|
7
|
+
# This class is a simple wrapper for the error response that the API returns. There are
|
8
|
+
# a couple of attributes:
|
9
|
+
#
|
10
|
+
# [code] The error code as described in the documentation
|
11
|
+
# [message] The associated error message
|
12
|
+
#
|
13
|
+
class Error
|
14
|
+
|
15
|
+
include Fleakr::Support::Object
|
16
|
+
|
17
|
+
flickr_attribute :code, :from => 'err@code'
|
18
|
+
flickr_attribute :message, :from => 'err@msg'
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = Group
|
5
|
+
#
|
6
|
+
# == Accessors
|
7
|
+
#
|
8
|
+
# [id] This group's ID
|
9
|
+
# [name] The name of the group
|
10
|
+
#
|
11
|
+
# == Associations
|
12
|
+
#
|
13
|
+
# [photos] The photos that are in this group
|
14
|
+
#
|
15
|
+
class Group
|
16
|
+
|
17
|
+
include Fleakr::Support::Object
|
18
|
+
|
19
|
+
flickr_attribute :id, :from => '@nsid'
|
20
|
+
flickr_attribute :name
|
21
|
+
flickr_attribute :adult_flag, :from => '@eighteenplus'
|
22
|
+
|
23
|
+
find_all :by_user_id, :call => 'people.getPublicGroups', :path => 'groups/group'
|
24
|
+
|
25
|
+
has_many :photos
|
26
|
+
|
27
|
+
scoped_search
|
28
|
+
|
29
|
+
# Is this group adult-only? (e.g. only 18+ allowed to view)
|
30
|
+
def adult?
|
31
|
+
(adult_flag == '1')
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects
|
3
|
+
|
4
|
+
# = Image
|
5
|
+
#
|
6
|
+
# This class wraps the functionality for saving remote images to disk. It's called
|
7
|
+
# by the Fleakr::Objects::Photo class to save an image with a specific size and would
|
8
|
+
# typically never be called directly.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# user = Fleakr.user('brownout')
|
13
|
+
# user.photos.first.small.save_to('/tmp')
|
14
|
+
#
|
15
|
+
# == Attributes
|
16
|
+
#
|
17
|
+
# [size] The name of this image's size (e.g. Square, Large, etc...)
|
18
|
+
# [width] The width of this image
|
19
|
+
# [height] The height of this image
|
20
|
+
# [url] The direct URL for this image
|
21
|
+
# [page] The page on Flickr that represents this photo
|
22
|
+
#
|
23
|
+
class Image
|
24
|
+
|
25
|
+
include Fleakr::Support::Object
|
26
|
+
|
27
|
+
flickr_attribute :width, :height
|
28
|
+
flickr_attribute :size, :from => '@label'
|
29
|
+
flickr_attribute :url, :from => '@source'
|
30
|
+
flickr_attribute :page, :from => '@url'
|
31
|
+
|
32
|
+
find_all :by_photo_id, :call => 'photos.getSizes', :path => 'sizes/size'
|
33
|
+
|
34
|
+
# The filename portion of the image (without the full URL)
|
35
|
+
def filename
|
36
|
+
self.url.match(/([^\/]+)$/)[1]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Save this image to the specified directory or file. If the target is a
|
40
|
+
# directory, the file will be created with the original filename from Flickr.
|
41
|
+
# If the target is a file, it will be saved with the specified name. In the
|
42
|
+
# case that the target file already exists, this method will overwrite it.
|
43
|
+
def save_to(target, prefix = nil)
|
44
|
+
destination = File.directory?(target) ? "#{target}/#{prefix}#{self.filename}" : "#{target}"
|
45
|
+
File.open(destination, 'w') {|f| f << Net::HTTP.get(URI.parse(self.url)) }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = Photo
|
5
|
+
#
|
6
|
+
# Handles both the retrieval of Photo objects from various associations (e.g. User / Set) as
|
7
|
+
# well as the ability to upload images to the Flickr site.
|
8
|
+
#
|
9
|
+
# == Attributes
|
10
|
+
#
|
11
|
+
# [id] The ID for this photo
|
12
|
+
# [title] The title of this photo
|
13
|
+
# [description] The description of this photo
|
14
|
+
# [secret] This photo's secret (used for sharing photo without permissions checking)
|
15
|
+
# [comment_count] Count of the comments attached to this photo
|
16
|
+
# [url] This photo's page on Flickr
|
17
|
+
# [square] The tiny square representation of this photo
|
18
|
+
# [thumbnail] The thumbnail for this photo
|
19
|
+
# [small] The small representation of this photo
|
20
|
+
# [medium] The medium representation of this photo
|
21
|
+
# [large] The large representation of this photo
|
22
|
+
# [original] The original photo
|
23
|
+
# [previous] The previous photo based on the current context
|
24
|
+
# [next] The next photo based on the current context
|
25
|
+
#
|
26
|
+
# == Associations
|
27
|
+
#
|
28
|
+
# [images] The underlying images for this photo.
|
29
|
+
# [tags] The tags for this photo.
|
30
|
+
# [comments] The comments associated with this photo
|
31
|
+
#
|
32
|
+
class Photo
|
33
|
+
|
34
|
+
# Available sizes for this photo
|
35
|
+
SIZES = [:square, :thumbnail, :small, :medium, :large, :original]
|
36
|
+
|
37
|
+
include Fleakr::Support::Object
|
38
|
+
extend Forwardable
|
39
|
+
|
40
|
+
def_delegators :context, :next, :previous
|
41
|
+
|
42
|
+
flickr_attribute :id, :from => ['@id', 'photoid']
|
43
|
+
flickr_attribute :title, :description, :secret, :posted, :taken, :url
|
44
|
+
flickr_attribute :farm_id, :from => '@farm'
|
45
|
+
flickr_attribute :server_id, :from => '@server'
|
46
|
+
flickr_attribute :owner_id, :from => ['@owner', 'owner@nsid']
|
47
|
+
flickr_attribute :updated, :from => '@lastupdate'
|
48
|
+
flickr_attribute :comment_count, :from => 'comments'
|
49
|
+
|
50
|
+
# TODO:
|
51
|
+
# * visibility
|
52
|
+
# * editability
|
53
|
+
# * usage
|
54
|
+
|
55
|
+
find_all :by_set_id, :using => :photoset_id, :call => 'photosets.getPhotos', :path => 'photoset/photo'
|
56
|
+
find_all :by_user_id, :call => 'people.getPublicPhotos', :path => 'photos/photo'
|
57
|
+
find_all :by_group_id, :call => 'groups.pools.getPhotos', :path => 'photos/photo'
|
58
|
+
|
59
|
+
find_one :by_id, :using => :photo_id, :call => 'photos.getInfo'
|
60
|
+
|
61
|
+
lazily_load :posted, :taken, :updated, :comment_count, :url, :description, :with => :load_info
|
62
|
+
|
63
|
+
has_many :images, :tags, :comments
|
64
|
+
|
65
|
+
# Upload the photo specified by <tt>filename</tt> to the user's Flickr account. When uploading,
|
66
|
+
# there are several options available (none are required):
|
67
|
+
#
|
68
|
+
# [:title] The title for this photo. Any string is allowed.
|
69
|
+
# [:description] The description for this photo. Any string is allowed.
|
70
|
+
# [:tags] A collection of tags for this photo. This can be a string or array of strings.
|
71
|
+
# [:viewable_by] Who can view this photo? Acceptable values are one of <tt>:everyone</tt>,
|
72
|
+
# <tt>:friends</tt> or <tt>:family</tt>. This can also take an array of values
|
73
|
+
# (e.g. <tt>[:friends, :family]</tt>) to make it viewable by friends and family.
|
74
|
+
# [:level] The safety level of this photo. Acceptable values are one of <tt>:safe</tt>,
|
75
|
+
# <tt>:moderate</tt>, or <tt>:restricted</tt>.
|
76
|
+
# [:type] The type of image this is. Acceptable values are one of <tt>:photo</tt>,
|
77
|
+
# <tt>:screenshot</tt>, or <tt>:other</tt>.
|
78
|
+
# [:hide?] Should this photo be hidden from public searches? Takes a boolean.
|
79
|
+
#
|
80
|
+
def self.upload(filename, options = {})
|
81
|
+
response = Fleakr::Api::UploadRequest.with_response!(filename, :create, options)
|
82
|
+
photo = Photo.new(response.body)
|
83
|
+
Photo.find_by_id(photo.id)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Replace the current photo's image with the one specified by filename. This
|
87
|
+
# call requires authentication.
|
88
|
+
#
|
89
|
+
def replace_with(filename)
|
90
|
+
response = Fleakr::Api::UploadRequest.with_response!(filename, :update, :photo_id => self.id)
|
91
|
+
self.populate_from(response.body)
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
# TODO: Refactor this to remove duplication w/ User#load_info - possibly in the lazily_load class method
|
96
|
+
def load_info # :nodoc:
|
97
|
+
response = Fleakr::Api::MethodRequest.with_response!('photos.getInfo', :photo_id => self.id)
|
98
|
+
self.populate_from(response.body)
|
99
|
+
end
|
100
|
+
|
101
|
+
def context # :nodoc:
|
102
|
+
@context ||= begin
|
103
|
+
response = Fleakr::Api::MethodRequest.with_response!('photos.getContext', :photo_id => self.id)
|
104
|
+
PhotoContext.new(response.body)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# The user who uploaded this photo. See Fleakr::Objects::User for additional information.
|
109
|
+
#
|
110
|
+
def owner
|
111
|
+
@owner ||= User.find_by_id(owner_id)
|
112
|
+
end
|
113
|
+
|
114
|
+
# When was this photo posted?
|
115
|
+
#
|
116
|
+
def posted_at
|
117
|
+
Time.at(posted.to_i)
|
118
|
+
end
|
119
|
+
|
120
|
+
# When was this photo taken?
|
121
|
+
#
|
122
|
+
def taken_at
|
123
|
+
Time.parse(taken)
|
124
|
+
end
|
125
|
+
|
126
|
+
# When was this photo last updated? This includes addition of tags and other metadata.
|
127
|
+
#
|
128
|
+
def updated_at
|
129
|
+
Time.at(updated.to_i)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Create methods to access image sizes by name
|
133
|
+
SIZES.each do |size|
|
134
|
+
define_method(size) do
|
135
|
+
images_by_size[size]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
def images_by_size
|
141
|
+
image_sizes = SIZES.inject({}) {|l,o| l.merge(o => nil)}
|
142
|
+
self.images.inject(image_sizes) {|l,o| l.merge!(o.size.downcase.to_sym => o) }
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|