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.
Files changed (82) hide show
  1. data/README.rdoc +350 -0
  2. data/Rakefile +41 -0
  3. data/lib/fleakr.rb +164 -0
  4. data/lib/fleakr/api.rb +8 -0
  5. data/lib/fleakr/api/file_parameter.rb +47 -0
  6. data/lib/fleakr/api/method_request.rb +66 -0
  7. data/lib/fleakr/api/option.rb +175 -0
  8. data/lib/fleakr/api/parameter.rb +35 -0
  9. data/lib/fleakr/api/parameter_list.rb +97 -0
  10. data/lib/fleakr/api/response.rb +35 -0
  11. data/lib/fleakr/api/upload_request.rb +75 -0
  12. data/lib/fleakr/api/value_parameter.rb +36 -0
  13. data/lib/fleakr/core_ext.rb +3 -0
  14. data/lib/fleakr/core_ext/false_class.rb +7 -0
  15. data/lib/fleakr/core_ext/hash.rb +22 -0
  16. data/lib/fleakr/core_ext/true_class.rb +7 -0
  17. data/lib/fleakr/objects.rb +13 -0
  18. data/lib/fleakr/objects/authentication_token.rb +60 -0
  19. data/lib/fleakr/objects/comment.rb +49 -0
  20. data/lib/fleakr/objects/contact.rb +31 -0
  21. data/lib/fleakr/objects/error.rb +22 -0
  22. data/lib/fleakr/objects/group.rb +36 -0
  23. data/lib/fleakr/objects/image.rb +50 -0
  24. data/lib/fleakr/objects/photo.rb +147 -0
  25. data/lib/fleakr/objects/photo_context.rb +49 -0
  26. data/lib/fleakr/objects/search.rb +30 -0
  27. data/lib/fleakr/objects/set.rb +51 -0
  28. data/lib/fleakr/objects/tag.rb +56 -0
  29. data/lib/fleakr/objects/user.rb +95 -0
  30. data/lib/fleakr/support.rb +2 -0
  31. data/lib/fleakr/support/attribute.rb +46 -0
  32. data/lib/fleakr/support/object.rb +112 -0
  33. data/lib/fleakr/version.rb +13 -0
  34. data/test/fixtures/auth.checkToken.xml +8 -0
  35. data/test/fixtures/auth.getFullToken.xml +8 -0
  36. data/test/fixtures/auth.getToken.xml +8 -0
  37. data/test/fixtures/contacts.getPublicList.xml +7 -0
  38. data/test/fixtures/groups.pools.getPhotos.xml +7 -0
  39. data/test/fixtures/people.findByEmail.xml +6 -0
  40. data/test/fixtures/people.findByUsername.xml +6 -0
  41. data/test/fixtures/people.getInfo.xml +18 -0
  42. data/test/fixtures/people.getPublicGroups.xml +7 -0
  43. data/test/fixtures/people.getPublicPhotos.xml +7 -0
  44. data/test/fixtures/photos.comments.getList.xml +7 -0
  45. data/test/fixtures/photos.getContext.xml +6 -0
  46. data/test/fixtures/photos.getInfo.xml +20 -0
  47. data/test/fixtures/photos.getSizes.xml +10 -0
  48. data/test/fixtures/photos.search.xml +7 -0
  49. data/test/fixtures/photosets.comments.getList.xml +7 -0
  50. data/test/fixtures/photosets.getList.xml +13 -0
  51. data/test/fixtures/photosets.getPhotos.xml +7 -0
  52. data/test/fixtures/tags.getListPhoto.xml +9 -0
  53. data/test/fixtures/tags.getListUser.xml +10 -0
  54. data/test/fixtures/tags.getRelated.xml +9 -0
  55. data/test/test_helper.rb +141 -0
  56. data/test/unit/fleakr/api/file_parameter_test.rb +63 -0
  57. data/test/unit/fleakr/api/method_request_test.rb +94 -0
  58. data/test/unit/fleakr/api/option_test.rb +179 -0
  59. data/test/unit/fleakr/api/parameter_list_test.rb +176 -0
  60. data/test/unit/fleakr/api/parameter_test.rb +34 -0
  61. data/test/unit/fleakr/api/response_test.rb +49 -0
  62. data/test/unit/fleakr/api/upload_request_test.rb +149 -0
  63. data/test/unit/fleakr/api/value_parameter_test.rb +41 -0
  64. data/test/unit/fleakr/core_ext/false_class_test.rb +13 -0
  65. data/test/unit/fleakr/core_ext/hash_test.rb +32 -0
  66. data/test/unit/fleakr/core_ext/true_class_test.rb +13 -0
  67. data/test/unit/fleakr/objects/authentication_token_test.rb +61 -0
  68. data/test/unit/fleakr/objects/comment_test.rb +66 -0
  69. data/test/unit/fleakr/objects/contact_test.rb +61 -0
  70. data/test/unit/fleakr/objects/error_test.rb +21 -0
  71. data/test/unit/fleakr/objects/group_test.rb +46 -0
  72. data/test/unit/fleakr/objects/image_test.rb +81 -0
  73. data/test/unit/fleakr/objects/photo_context_test.rb +80 -0
  74. data/test/unit/fleakr/objects/photo_test.rb +246 -0
  75. data/test/unit/fleakr/objects/search_test.rb +74 -0
  76. data/test/unit/fleakr/objects/set_test.rb +82 -0
  77. data/test/unit/fleakr/objects/tag_test.rb +98 -0
  78. data/test/unit/fleakr/objects/user_test.rb +91 -0
  79. data/test/unit/fleakr/support/attribute_test.rb +126 -0
  80. data/test/unit/fleakr/support/object_test.rb +129 -0
  81. data/test/unit/fleakr_test.rb +171 -0
  82. 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,3 @@
1
+ require 'fleakr/core_ext/hash'
2
+ require 'fleakr/core_ext/false_class'
3
+ require 'fleakr/core_ext/true_class'
@@ -0,0 +1,7 @@
1
+ class FalseClass # :nodoc:
2
+
3
+ def to_i
4
+ 0
5
+ end
6
+
7
+ 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,7 @@
1
+ class TrueClass # :nodoc:
2
+
3
+ def to_i
4
+ 1
5
+ end
6
+
7
+ 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