mrpunkin-flickr_fu 0.3.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 (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 +160 -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 +313 -0
  20. data/lib/flickr/photo_response.rb +37 -0
  21. data/lib/flickr/photos.rb +250 -0
  22. data/lib/flickr/photoset.rb +55 -0
  23. data/lib/flickr/photosets.rb +52 -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 +151 -0
@@ -0,0 +1,160 @@
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
+ magic = options.delete(:magic)
86
+ magic = true if magic.nil?
87
+
88
+ options.merge!(:api_key => @api_key, :method => method)
89
+ sign_request(options)
90
+
91
+ rsp = request_over_http(options, http_method, endpoint)
92
+
93
+ return rsp unless magic
94
+
95
+ rsp = '<rsp stat="ok"></rsp>' if rsp == ""
96
+ xm = XmlMagic.new(rsp)
97
+
98
+ if xm[:stat] == 'ok'
99
+ xm
100
+ else
101
+ raise Flickr::Errors.error_for(xm.err[:code].to_i, xm.err[:msg])
102
+ end
103
+ end
104
+
105
+ # alters your api parameters to include a signiture and authorization token
106
+ #
107
+ # Params
108
+ # * options (Required)
109
+ # the hash of parameters to be passed to the send_request
110
+ # * authorize (Optional)
111
+ # boolean value to determine if the call with include an auth_token (Defaults to true)
112
+ #
113
+ def sign_request(options, authorize = true)
114
+ options.merge!(:auth_token => self.auth.token(false).to_s, :api_key => @api_key) if authorize and self.auth.token(false)
115
+ options.delete(:api_sig)
116
+ options.merge!(:api_sig => Digest::MD5.hexdigest(@api_secret + options.to_a.sort_by{|k| k[0].to_s}.flatten.join)) if @api_secret
117
+ end
118
+
119
+ # creates and/or returns the Flickr::Test object
120
+ def test() @test ||= Flickr::Test.new(self) end
121
+
122
+ # creates and/or returns the Flickr::Photos object
123
+ def photos() @photos ||= Flickr::Photos.new(self) end
124
+
125
+ # creates and/or returns the Flickr::Photos object
126
+ def photosets() @photosets ||= Flickr::Photosets.new(self) end
127
+
128
+ # creates and/or returns the Flickr::People object
129
+ def people() @people ||= Flickr::People.new(self) end
130
+
131
+ # creates and/or returns the Flickr::Auth object
132
+ def auth() @auth ||= Flickr::Auth.new(self) end
133
+
134
+ # creates and/or returns the Flickr::Uploader object
135
+ def uploader() @uploader ||= Flickr::Uploader.new(self) end
136
+
137
+ # creates and/or returns the Flickr::Contacts object
138
+ def contacts() @contacts ||= Flickr::Contacts.new(self) end
139
+
140
+ # creates and/or returns the Flickr::Urls object
141
+ def urls() @urls ||= Flickr::Urls.new(self) end
142
+
143
+ def attributes_hash(rsp)
144
+ Hash.from_xml(rsp)["rsp"]
145
+ end
146
+
147
+ protected
148
+
149
+ # For easier testing. You can mock this method with a XML file you're expecting to receive
150
+ def request_over_http(options, http_method, endpoint)
151
+ if http_method == :get
152
+ api_call = endpoint + "?" + options.collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&')
153
+ Net::HTTP.get(URI.parse(api_call))
154
+ else
155
+ Net::HTTP.post_form(URI.parse(endpoint), options).body
156
+ end
157
+ end
158
+
159
+ end
160
+ 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
data/lib/flickr/geo.rb ADDED
@@ -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