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
data/lib/fleakr/api.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "fleakr/api/response"
2
+ require "fleakr/api/method_request"
3
+ require "fleakr/api/option"
4
+ require "fleakr/api/upload_request"
5
+ require "fleakr/api/parameter_list"
6
+ require "fleakr/api/parameter"
7
+ require "fleakr/api/value_parameter"
8
+ require "fleakr/api/file_parameter"
@@ -0,0 +1,47 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = FileParameter
5
+ #
6
+ # Parameter class to encapsulate file data sent to the Flickr upload API
7
+ #
8
+ class FileParameter < Parameter
9
+
10
+ MIME_TYPES = {
11
+ '.jpg' => 'image/jpeg',
12
+ '.png' => 'image/png',
13
+ '.gif' => 'image/gif'
14
+ }
15
+
16
+ # Create a parameter with name and specified filename
17
+ #
18
+ def initialize(name, filename)
19
+ @filename = filename
20
+ super(name, false)
21
+ end
22
+
23
+ # Discover MIME type by file extension using MIME_TYPES constant
24
+ #
25
+ def mime_type
26
+ MIME_TYPES[File.extname(@filename)]
27
+ end
28
+
29
+ # File data (from @filename) to pass to the Flickr API
30
+ #
31
+ def value
32
+ @value ||= File.read(@filename)
33
+ end
34
+
35
+ # Generate a form representation of this file for upload (as multipart/form-data)
36
+ #
37
+ def to_form
38
+ "Content-Disposition: form-data; name=\"#{self.name}\"; filename=\"#{@filename}\"\r\n" +
39
+ "Content-Type: #{self.mime_type}\r\n" +
40
+ "\r\n" +
41
+ "#{self.value}\r\n"
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,66 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = MethodRequest
5
+ #
6
+ # Handles all API requests that are non-upload related. For upload requests see the
7
+ # UploadRequest class.
8
+ #
9
+ class MethodRequest
10
+ attr_reader :parameters, :method
11
+
12
+ # Makes a request to the Flickr API and returns a valid Response object. If
13
+ # there are errors on the response it will raise an ApiError exception. See
14
+ # MethodRequest#new for details about the additional parameters
15
+ #
16
+ def self.with_response!(method, additional_parameters = {})
17
+ request = self.new(method, additional_parameters)
18
+ response = request.send
19
+
20
+ raise(Fleakr::ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
21
+
22
+ response
23
+ end
24
+
25
+ # Create a new request for the specified API method and pass along any additional
26
+ # parameters. The Flickr API uses namespacing for its methods - this is optional
27
+ # when calling this method.
28
+ #
29
+ # This must be called after initializing the library with the required API key
30
+ # see (#Fleakr.api_key=)
31
+ #
32
+ # The <tt>additional_parameters</tt> is a list of parameters to pass directly to
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).
36
+ #
37
+ def initialize(method, additional_parameters = {})
38
+ @parameters = ParameterList.new(additional_parameters)
39
+
40
+ self.method = method
41
+ end
42
+
43
+ def method=(method) # :nodoc:
44
+ @method = method.sub(/^(flickr\.)?/, 'flickr.')
45
+ @parameters << ValueParameter.new('method', @method)
46
+ end
47
+
48
+ def send # :nodoc:
49
+ logger.info("Sending request to: #{endpoint_uri}")
50
+ response_xml = Net::HTTP.get(endpoint_uri)
51
+ logger.debug("Response data:\n#{response_xml}")
52
+
53
+ Response.new(response_xml)
54
+ end
55
+
56
+ private
57
+ def endpoint_uri
58
+ uri = URI.parse('http://api.flickr.com/services/rest/')
59
+ uri.query = self.parameters.to_query
60
+ uri
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
@@ -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 then 1
125
+ when :moderate then 2
126
+ when :restricted then 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 then 1
147
+ when :screenshot then 2
148
+ when :other then 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
@@ -0,0 +1,35 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = Parameter
5
+ #
6
+ # Base class for other parameters that get passed to the Flickr API - see
7
+ # #FileParameter and #ValueParameter for examples
8
+ #
9
+ class Parameter
10
+
11
+ attr_reader :name
12
+
13
+ # A new named parameter (never used directly)
14
+ #
15
+ def initialize(name, include_in_signature = true)
16
+ @name = name
17
+ @include_in_signature = include_in_signature
18
+ end
19
+
20
+ # Should this parameter be used when generating the signature?
21
+ #
22
+ def include_in_signature?
23
+ (@include_in_signature == true) ? true : false
24
+ end
25
+
26
+ # Used for sorting when generating a signature
27
+ #
28
+ def <=>(other)
29
+ self.name <=> other.name
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,97 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = ParameterList
5
+ #
6
+ # Represents a list of parameters that get passed as part of a
7
+ # MethodRequest or UploadRequest. These can be transformed as necessary
8
+ # into query strings (using #to_query) or form data (using #to_form)
9
+ #
10
+ class ParameterList
11
+
12
+ # Create a new parameter list with optional parameters:
13
+ # [:authenticate?] Request will automatically be authenticated if Fleakr.token is available
14
+ # set this to false to force it not to authenticate
15
+ #
16
+ # Any additional name / value pairs will be created as individual
17
+ # ValueParameters as part of the list. Example:
18
+ #
19
+ # >> list = Fleakr::Api::ParameterList.new(:foo => 'bar')
20
+ # => #<Fleakr::Api::ParameterList:0x1656e6c @list=... >
21
+ # >> list[:foo]
22
+ # => #<Fleakr::Api::ValueParameter:0x1656da4 @include_in_signature=true, @name="foo", @value="bar">
23
+ #
24
+ def initialize(options = {})
25
+ # TODO: need to find a way to move the unexpected behavior in Fleakr.token elsewhere
26
+ @api_options = options.extract!(:authenticate?)
27
+
28
+ @list = Hash.new
29
+
30
+ options.each {|k,v| self << ValueParameter.new(k.to_s, v) }
31
+
32
+ self << ValueParameter.new('api_key', Fleakr.api_key)
33
+ self << ValueParameter.new('auth_token', Fleakr.token.value) if authenticate?
34
+ end
35
+
36
+ # Add a new parameter (ValueParameter / FileParameter) to the list
37
+ #
38
+ def <<(parameter)
39
+ @list.merge!(parameter.name => parameter)
40
+ end
41
+
42
+ # Should this parameter list be signed?
43
+ #
44
+ def sign?
45
+ !Fleakr.shared_secret.blank?
46
+ end
47
+
48
+ # Should we send the auth_token with the request?
49
+ #
50
+ def authenticate?
51
+ @api_options.has_key?(:authenticate?) ? @api_options[:authenticate?] : !Fleakr.token.blank?
52
+ end
53
+
54
+ # Access an individual parameter by key (symbol or string)
55
+ #
56
+ def [](key)
57
+ list[key.to_s]
58
+ end
59
+
60
+ def boundary # :nodoc:
61
+ @boundary ||= Digest::MD5.hexdigest(rand.to_s)
62
+ end
63
+
64
+ # Generate the query string representation of this parameter
65
+ # list - e.g. <tt>foo=bar&blee=baz</tt>
66
+ #
67
+ def to_query
68
+ list.values.map {|element| element.to_query }.join('&')
69
+ end
70
+
71
+ # Generate the form representation of this parameter list including the
72
+ # boundary
73
+ #
74
+ def to_form
75
+ form = list.values.map {|p| "--#{self.boundary}\r\n#{p.to_form}" }.join
76
+ form << "--#{self.boundary}--"
77
+
78
+ form
79
+ end
80
+
81
+ def signature # :nodoc:
82
+ parameters_to_sign = @list.values.reject {|p| !p.include_in_signature? }
83
+ signature_text = parameters_to_sign.sort.map {|p| "#{p.name}#{p.value}" }.join
84
+
85
+ Digest::MD5.hexdigest("#{Fleakr.shared_secret}#{signature_text}")
86
+ end
87
+
88
+ private
89
+ def list
90
+ list = @list
91
+ list.merge!('api_sig' => ValueParameter.new('api_sig', signature, false)) if self.sign?
92
+
93
+ list
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,35 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = Response
5
+ #
6
+ # Response objects contain Hpricot documents that are traversed and parsed by
7
+ # the model objects. This class is never called directly but is instantiated
8
+ # during the request cycle (see: Fleakr::Api::MethodRequest.with_response!)
9
+ #
10
+ class Response
11
+
12
+ # Creates a new response from a raw XML string returned from a Request
13
+ def initialize(response_xml)
14
+ @response_xml = response_xml
15
+ end
16
+
17
+ # Return a document-based representation of the XML contained in the
18
+ # API response. This is an Hpricot document object
19
+ def body
20
+ @body ||= Hpricot.XML(@response_xml)
21
+ end
22
+
23
+ # Did the response from the API contain errors?
24
+ def error?
25
+ (self.body/'rsp').attr('stat') != 'ok'
26
+ end
27
+
28
+ # Access the API error if one exists
29
+ def error
30
+ Fleakr::Objects::Error.new(self.body) if self.error?
31
+ end
32
+
33
+ end
34
+ end
35
+ end