maciej-flickr_fu 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.gitignore +13 -0
  2. data/LICENSE +22 -0
  3. data/README +147 -0
  4. data/Rakefile +73 -0
  5. data/VERSION.yml +4 -0
  6. data/flickr_fu.gemspec +117 -0
  7. data/lib/flickr/auth.rb +76 -0
  8. data/lib/flickr/base.rb +151 -0
  9. data/lib/flickr/comment.rb +16 -0
  10. data/lib/flickr/contact.rb +16 -0
  11. data/lib/flickr/contacts.rb +55 -0
  12. data/lib/flickr/errors.rb +20 -0
  13. data/lib/flickr/geo.rb +42 -0
  14. data/lib/flickr/license.rb +24 -0
  15. data/lib/flickr/location.rb +15 -0
  16. data/lib/flickr/note.rb +16 -0
  17. data/lib/flickr/people.rb +54 -0
  18. data/lib/flickr/person.rb +82 -0
  19. data/lib/flickr/photo.rb +303 -0
  20. data/lib/flickr/photo_response.rb +37 -0
  21. data/lib/flickr/photos.rb +246 -0
  22. data/lib/flickr/photoset.rb +36 -0
  23. data/lib/flickr/photosets.rb +36 -0
  24. data/lib/flickr/size.rb +16 -0
  25. data/lib/flickr/status.rb +19 -0
  26. data/lib/flickr/test.rb +31 -0
  27. data/lib/flickr/token.rb +22 -0
  28. data/lib/flickr/uploader.rb +162 -0
  29. data/lib/flickr/urls.rb +44 -0
  30. data/lib/flickr_fu.rb +48 -0
  31. data/spec/fixtures/flickr/contacts/get_list-fail-99.xml +4 -0
  32. data/spec/fixtures/flickr/contacts/get_public_list-0.xml +7 -0
  33. data/spec/fixtures/flickr/photos/geo/get_location-0.xml +11 -0
  34. data/spec/fixtures/flickr/photos/geo/get_location-fail-2.xml +4 -0
  35. data/spec/fixtures/flickr/photos/get_info-0.xml +41 -0
  36. data/spec/fixtures/flickr/photos/get_info-1.xml +19 -0
  37. data/spec/fixtures/flickr/photos/get_sizes-0.xml +10 -0
  38. data/spec/fixtures/flickr/photos/get_sizes-1.xml +8 -0
  39. data/spec/fixtures/flickr/photos/licenses/get_info.xml +12 -0
  40. data/spec/fixtures/flickr/photosets/get_list-0.xml +13 -0
  41. data/spec/fixtures/flickr/photosets/get_photos-0.xml +7 -0
  42. data/spec/fixtures/flickr/test/echo-0.xml +5 -0
  43. data/spec/fixtures/flickr/test/null-fail-99.xml +4 -0
  44. data/spec/fixtures/flickr/urls/get_group-0.xml +4 -0
  45. data/spec/fixtures/flickr/urls/get_group-fail-1.xml +4 -0
  46. data/spec/fixtures/flickr/urls/get_user_photos-0.xml +4 -0
  47. data/spec/fixtures/flickr/urls/get_user_photos-fail-1.xml +4 -0
  48. data/spec/fixtures/flickr/urls/get_user_photos-fail-2.xml +4 -0
  49. data/spec/fixtures/flickr/urls/get_user_profile-0.xml +4 -0
  50. data/spec/fixtures/flickr/urls/get_user_profile-fail-1.xml +4 -0
  51. data/spec/fixtures/flickr/urls/get_user_profile-fail-2.xml +4 -0
  52. data/spec/fixtures/flickr/urls/lookup_group-0.xml +6 -0
  53. data/spec/fixtures/flickr/urls/lookup_group-fail-1.xml +4 -0
  54. data/spec/fixtures/flickr/urls/lookup_user-0.xml +6 -0
  55. data/spec/fixtures/flickr/videos/get_info-0.xml +31 -0
  56. data/spec/fixtures/flickr/videos/get_sizes-0.xml +13 -0
  57. data/spec/flickr/base_spec.rb +97 -0
  58. data/spec/flickr/contacts_spec.rb +47 -0
  59. data/spec/flickr/errors_spec.rb +21 -0
  60. data/spec/flickr/geo_spec.rb +20 -0
  61. data/spec/flickr/photo_spec.rb +123 -0
  62. data/spec/flickr/photos_spec.rb +50 -0
  63. data/spec/flickr/photosets_spec.rb +49 -0
  64. data/spec/flickr/test_spec.rb +34 -0
  65. data/spec/flickr/urls_spec.rb +99 -0
  66. data/spec/spec.opts +4 -0
  67. data/spec/spec_helper.rb +20 -0
  68. metadata +149 -0
@@ -0,0 +1,151 @@
1
+ module Flickr
2
+ def self.new(*params)
3
+ Flickr::Base.new(*params)
4
+ end
5
+
6
+ class Base
7
+ attr_reader :api_key, :api_secret, :token_cache, :token
8
+
9
+ REST_ENDPOINT = 'http://api.flickr.com/services/rest/'
10
+ AUTH_ENDPOINT = 'http://flickr.com/services/auth/'
11
+ UPLOAD_ENDPOINT = 'http://api.flickr.com/services/upload/'
12
+
13
+ # create a new flickr object
14
+ #
15
+ # You can either pass a hash with the following attributes:
16
+ #
17
+ # * :key (Required)
18
+ # the API key
19
+ # * :secret (Required)
20
+ # the API secret
21
+ # * :token (Optional)
22
+ # Flickr::Auth::Token object
23
+ #
24
+ # or:
25
+ #
26
+ # * config_file (Required)
27
+ # yaml file to load configuration from
28
+ # * options (Optional)
29
+ # hash containing any of the two options
30
+ # * token_cache
31
+ # location of the token cache file. This will override the setting in the config file
32
+ # * environment
33
+ # section in the config file that flickr_fu should look for the API key and secret
34
+ # Useful when using with Rails
35
+ #
36
+ # Config Example (yaml file)
37
+ # ---
38
+ # key: YOUR_API_KEY
39
+ # secret: YOUR_API_SECRET
40
+ # token_cache: token.yml
41
+ #
42
+ # Example config file with two environments:
43
+ # ---
44
+ # development:
45
+ # key: YOUR_DEVELOPMENT_API_KEY
46
+ # secret: YOUR_DEVELOPMENT_API_SECRET
47
+ # production:
48
+ # key: YOUR_PRODUCTION_API_KEY
49
+ # secret: YOUR_PRODUCTION_API_SECRET
50
+ def initialize(config_param, options_param = {})
51
+ if options_param.is_a? String
52
+ options = {:token_cache => options_param}
53
+ else
54
+ options = options_param
55
+ end
56
+ if config_param.is_a? String
57
+ config = YAML.load_file(config_param)
58
+ config = config[options[:environment]] if options.has_key? :environment
59
+ else
60
+ config = config_param
61
+ end
62
+ @api_key = config[:key] || config["key"]
63
+ @api_secret = config[:secret] || config["secret"]
64
+ @token_cache = options[:token_cache] || config["token_cache"]
65
+ @token = config[:token] || options[:token]
66
+ raise 'config file must contain an api key and secret' unless @api_key and @api_secret
67
+ raise 'you cannot specify both the token and token_cache' if @token and @token_cache
68
+ end
69
+
70
+ # sends a request to the flickr REST api
71
+ #
72
+ # Params
73
+ # * method (Required)
74
+ # name of the flickr method (ex. flickr.photos.search)
75
+ # * options (Optional)
76
+ # hash of query parameters, you do not need to include api_key, api_sig or auth_token because these are added automatically
77
+ # * http_method (Optional)
78
+ # choose between a GET and POST http request. Valid options are:
79
+ # :get (DEFAULT)
80
+ # :post
81
+ # * endpoint (Optional)
82
+ # url of the api endpoint
83
+ #
84
+ def send_request(method, options = {}, http_method = :get, endpoint = REST_ENDPOINT)
85
+ options.merge!(:api_key => @api_key, :method => method)
86
+ sign_request(options)
87
+
88
+ rsp = request_over_http(options, http_method, endpoint)
89
+
90
+ rsp = '<rsp stat="ok"></rsp>' if rsp == ""
91
+ xm = XmlMagic.new(rsp)
92
+
93
+ if xm[:stat] == 'ok'
94
+ xm
95
+ else
96
+ raise Flickr::Errors.error_for(xm.err[:code].to_i, xm.err[:msg])
97
+ end
98
+ end
99
+
100
+ # alters your api parameters to include a signiture and authorization token
101
+ #
102
+ # Params
103
+ # * options (Required)
104
+ # the hash of parameters to be passed to the send_request
105
+ # * authorize (Optional)
106
+ # boolean value to determine if the call with include an auth_token (Defaults to true)
107
+ #
108
+ def sign_request(options, authorize = true)
109
+ options.merge!(:auth_token => self.auth.token(false).to_s, :api_key => @api_key) if authorize and self.auth.token(false)
110
+ options.delete(:api_sig)
111
+ options.merge!(:api_sig => Digest::MD5.hexdigest(@api_secret + options.to_a.sort_by{|k| k[0].to_s}.flatten.join)) if @api_secret
112
+ end
113
+
114
+ # creates and/or returns the Flickr::Test object
115
+ def test() @test ||= Flickr::Test.new(self) end
116
+
117
+ # creates and/or returns the Flickr::Photos object
118
+ def photos() @photos ||= Flickr::Photos.new(self) end
119
+
120
+ # creates and/or returns the Flickr::Photos object
121
+ def photosets() @photosets ||= Flickr::Photosets.new(self) end
122
+
123
+ # creates and/or returns the Flickr::People object
124
+ def people() @people ||= Flickr::People.new(self) end
125
+
126
+ # creates and/or returns the Flickr::Auth object
127
+ def auth() @auth ||= Flickr::Auth.new(self) end
128
+
129
+ # creates and/or returns the Flickr::Uploader object
130
+ def uploader() @uploader ||= Flickr::Uploader.new(self) end
131
+
132
+ # creates and/or returns the Flickr::Contacts object
133
+ def contacts() @contacts ||= Flickr::Contacts.new(self) end
134
+
135
+ # creates and/or returns the Flickr::Urls object
136
+ def urls() @urls ||= Flickr::Urls.new(self) end
137
+
138
+ protected
139
+
140
+ # For easier testing. You can mock this method with a XML file you're expecting to receive
141
+ def request_over_http(options, http_method, endpoint)
142
+ if http_method == :get
143
+ api_call = endpoint + "?" + options.collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&')
144
+ Net::HTTP.get(URI.parse(api_call))
145
+ else
146
+ Net::HTTP.post_form(URI.parse(endpoint), options).body
147
+ end
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,16 @@
1
+ # wrapping class to hold a flickr comment
2
+ #
3
+ class Flickr::Photos::Comment
4
+ attr_accessor :id, :comment, :author, :author_name, :created_at, :permalink
5
+
6
+ # create a new instance of a flickr comment.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the comment object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # wrapping class to hold a flickr contact
2
+ #
3
+ class Flickr::Contacts::Contact
4
+ attr_accessor :nsid, :friend, :family, :iconfarm, :iconserver, :location, :username, :ignored, :realname, :path_alias
5
+
6
+ # create a new instance of a flickr note.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the contact object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,55 @@
1
+ class Flickr::Contacts < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # Get a user's public contact list.
7
+ #
8
+ # Params
9
+ # * id (Required)
10
+ # the nsid of the user to get information for
11
+ #
12
+ def get_public_list(id, options={})
13
+ options.merge!({:user_id => id})
14
+ rsp = @flickr.send_request('flickr.contacts.getPublicList', options)
15
+ collect_contacts(rsp)
16
+ end
17
+
18
+
19
+ # Get the authorized user's contact list.
20
+ #
21
+ def get_list(options={})
22
+ rsp = @flickr.send_request('flickr.contacts.getList', options)
23
+ collect_contacts(rsp)
24
+ end
25
+
26
+
27
+ protected
28
+ def collect_contacts(rsp)
29
+ contacts = []
30
+ return contacts unless rsp
31
+ if rsp.contacts.contact
32
+ rsp.contacts.contact.each do |contact|
33
+ attributes = create_attributes(contact)
34
+ contacts << Contact.new(attributes)
35
+ end
36
+ end
37
+ return contacts
38
+ end
39
+
40
+ def create_attributes(contact)
41
+ {
42
+ :nsid => contact[:nsid],
43
+ :path_alias => contact[:path_alias],
44
+ :username => contact[:username],
45
+ :iconfarm => contact[:iconfarm],
46
+ :iconserver => contact[:iconserver],
47
+ :ignored => contact[:ignored],
48
+ :friend => contact[:friend],
49
+ :family => contact[:family],
50
+ :realname => contact[:realname],
51
+ :location => contact[:location]
52
+ }
53
+ end
54
+
55
+ end
@@ -0,0 +1,20 @@
1
+ module Flickr
2
+ class Error < RuntimeError
3
+ attr_accessor :code
4
+ end
5
+
6
+
7
+ class Errors
8
+
9
+ # Method used for raising the appropriate error class for a given error code.
10
+ # Currently raises only Flickr::Error
11
+ def self.error_for(code, message)
12
+ raise RuntimeError.new("Internal error. Flickr API error not identified or unknown error.") if (code.nil? || message.nil? || message.empty?)
13
+ raise RuntimeError.new("Internal error. Unknown error.") if code.to_i == 0 # We assume that error code 0 is never returned
14
+ e = Flickr::Error.new("#{code}: #{message}")
15
+ e.code = code
16
+ raise e
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,42 @@
1
+ class Flickr::Photos::Geo < Flickr::Base
2
+
3
+ def initialize(flickr)
4
+ @flickr = flickr
5
+ end
6
+
7
+ # Get the geo data (latitude and longitude and the accuracy level) of a photo.
8
+ #
9
+ # Params
10
+ # * photo_id (Required)
11
+ #
12
+ # Returns Flickr::Photos::Location object containing photo location
13
+ # or nil if photo is not geotagged.
14
+ def get_location(photo_id)
15
+ # begin
16
+ rsp = @flickr.send_request('flickr.photos.geo.getLocation', {:photo_id => photo_id})
17
+ Flickr::Photos::Location.new(:latitude => rsp.photo.location[:latitude].to_f,
18
+ :longitude => rsp.photo.location[:longitude].to_f, :accuracy => rsp.photo.location[:accuracy].to_i)
19
+ end
20
+
21
+ # Sets the geo data(latitude and longitude and the accuracy level) of a photo.
22
+ #
23
+ # Params
24
+ # * photo_id (Required)
25
+ # * latittude (Requried)
26
+ # * longitude (Required)
27
+ # * accuracy (Optional)
28
+ #
29
+ # Returns true if successful, raises an error otherwise.
30
+ def set_location(photo_id, lat, lon, accuracy = nil)
31
+ request_options = {:photo_id => photo_id, :lat => lat, :lon => lon}
32
+ request_options[:accuracy] = accuracy if !accuracy.nil?
33
+ @flickr.send_request('flickr.photos.geo.setLocation', request_options, :post)
34
+ true
35
+ end
36
+
37
+ def remove_location(photo_id)
38
+ request_options = {:photo_id => photo_id}
39
+ @flickr.send_request('flickr.photos.geo.removeLocation', request_options, :post)
40
+ true
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ class Flickr::Photos::License
2
+ attr_accessor :id, :name, :url
3
+
4
+ # create a new instance of a flickr photo license.
5
+ #
6
+ # Params
7
+ # * attributes (Required)
8
+ # a hash of attributes used to set the initial values of the license object
9
+ def initialize(attributes)
10
+ attributes.each do |k,v|
11
+ send("#{k}=", v)
12
+ end
13
+ end
14
+
15
+ def == o
16
+ return false unless o.respond_to?(:id) && o.respond_to?(:name) && o.respond_to?(:url)
17
+ return true if id == o.id && name == o.name && url == o.url
18
+ false
19
+ end
20
+
21
+ def eql? o
22
+ return self == o
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ class Flickr::Photos::Location
2
+
3
+ attr_accessor :latitude, :longitude, :accuracy
4
+
5
+ # Create an instance of Flickr::Photos::Location
6
+ #
7
+ # Params
8
+ # * attributes (Required)
9
+ # a hash of attributes used to set the initial values of the Location object
10
+ def initialize(attributes)
11
+ attributes.each do |k,v|
12
+ send("#{k}=", v)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # wrapping class to hold a flickr note
2
+ #
3
+ class Flickr::Photos::Note
4
+ attr_accessor :id, :note, :author, :author_name, :x, :y, :width, :height
5
+
6
+ # create a new instance of a flickr note.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the note object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ class Flickr::People < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # Get information about a user.
7
+ #
8
+ # Params
9
+ # * id (Required)
10
+ # the nsid of the user to get information for
11
+ #
12
+ def find_by_id(id)
13
+ rsp = @flickr.send_request('flickr.people.getInfo', {:user_id => id})
14
+
15
+ Person.new(@flickr, :nsid => rsp.person[:nsid],
16
+ :is_admin => (rsp.person[:isadmin] == "1" ? true : false),
17
+ :is_pro => (rsp.person[:ispro] == "1" ? true : false),
18
+ :icon_server => rsp.person[:iconserver],
19
+ :icon_farm => rsp.person[:iconfarm],
20
+ :username => rsp.person.username.to_s,
21
+ :realname => rsp.person.realname.to_s,
22
+ :mbox_sha1sum => rsp.person.mbox_sha1sum.to_s,
23
+ :location => rsp.person.location.to_s,
24
+ :photos_url => rsp.person.photosurl.to_s,
25
+ :profile_url => rsp.person.profileurl.to_s,
26
+ :photo_count => rsp.person.photos.count.to_s.to_i,
27
+ :photo_first_upload => (Time.at(rsp.person.photos.firstdate.to_s.to_i) rescue nil),
28
+ :photo_first_taken => (Time.parse(rsp.person.photos.firstdatetaken.to_s) rescue nil))
29
+ end
30
+
31
+ # Get information about a user.
32
+ #
33
+ # Params
34
+ # * username (Required)
35
+ # the username of the user to get information for
36
+ #
37
+ def find_by_username(username)
38
+ rsp = @flickr.send_request('flickr.people.findByUsername', {:username => username})
39
+
40
+ find_by_id(rsp.user[:nsid])
41
+ end
42
+
43
+ # Get information about a user.
44
+ #
45
+ # Params
46
+ # * email (Required)
47
+ # the email of the user to get information for
48
+ #
49
+ def find_by_email(email)
50
+ rsp = @flickr.send_request('flickr.people.findByEmail', {:find_email => email})
51
+
52
+ find_by_id(rsp.user[:nsid])
53
+ end
54
+ end
@@ -0,0 +1,82 @@
1
+ # wrapping class to hold an flickr photo
2
+ #
3
+ class Flickr::People::Person
4
+ attr_accessor :username, :nsid, :is_admin, :is_pro, :icon_server, :icon_farm, :realname, :mbox_sha1sum, :location, :photos_url, :profile_url, :photo_count, :photo_first_upload, :photo_first_taken
5
+
6
+ # create a new instance of a flickr person.
7
+ #
8
+ # Params
9
+ # * flickr (Required)
10
+ # the flickr object
11
+ # * attributes (Required)
12
+ # a hash of attributes used to set the initial values of the person object
13
+ def initialize(flickr, attributes)
14
+ @flickr = flickr
15
+ attributes.each do |k,v|
16
+ send("#{k}=", v)
17
+ end
18
+ end
19
+
20
+ def buddy_icon
21
+ @buddy_icon ||= if icon_server.to_i > 0
22
+ "http://farm#{icon_farm}.static.flickr.com/#{icon_server}/buddyicons/#{nsid}.jpg"
23
+ else
24
+ 'http://www.flickr.com/images/buddyicon.jpg'
25
+ end
26
+ end
27
+
28
+ # Get a list of public photos for the given user.
29
+ #
30
+ # Options
31
+ # * safe_search (Optional)
32
+ # Safe search setting:
33
+ # 1 for safe.
34
+ # 2 for moderate.
35
+ # 3 for restricted.
36
+ # (Please note: Un-authed calls can only see Safe content.)
37
+ # * per_page (Optional)
38
+ # Number of photos to return per page. If this argument is omitted, it defaults to 100. The maximum allowed value is 500.
39
+ # * page (Optional)
40
+ # The page of results to return. If this argument is omitted, it defaults to 1.
41
+ def public_photos(options = {})
42
+ options.merge!({:user_id => self.nsid, :extras => "license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo,tags,machine_tags,o_dims,views,media"})
43
+
44
+ rsp = @flickr.send_request('flickr.people.getPublicPhotos', options)
45
+
46
+ returning Flickr::Photos::PhotoResponse.new(:page => rsp.photos[:page].to_i,
47
+ :pages => rsp.photos[:pages].to_i,
48
+ :per_page => rsp.photos[:perpage].to_i,
49
+ :total => rsp.photos[:total].to_i,
50
+ :photos => [],
51
+ :api => self,
52
+ :method => 'public_photos',
53
+ :options => options) do |photos|
54
+ rsp.photos.photo.each do |photo|
55
+ attributes = {:id => photo[:id],
56
+ :owner => photo[:owner],
57
+ :secret => photo[:secret],
58
+ :server => photo[:server],
59
+ :farm => photo[:farm],
60
+ :title => photo[:title],
61
+ :is_public => photo[:ispublic],
62
+ :is_friend => photo[:isfriend],
63
+ :is_family => photo[:isfamily],
64
+ :license_id => photo[:license].to_i,
65
+ :uploaded_at => (Time.at(photo[:dateupload].to_i) rescue nil),
66
+ :taken_at => (Time.parse(photo[:datetaken]) rescue nil),
67
+ :owner_name => photo[:ownername],
68
+ :icon_server => photo[:icon_server],
69
+ :original_format => photo[:originalformat],
70
+ :updated_at => (Time.at(photo[:lastupdate].to_i) rescue nil),
71
+ :geo => photo[:geo],
72
+ :tags => photo[:tags],
73
+ :machine_tags => photo[:machine_tags],
74
+ :o_dims => photo[:o_dims],
75
+ :views => photo[:views].to_i,
76
+ :media => photo[:media]}
77
+
78
+ photos << Flickr::Photos::Photo.new(@flickr, attributes)
79
+ end if rsp.photos.photo
80
+ end
81
+ end
82
+ end