completelynovel-amazon-product-advertising-api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/EXAMPLE.txt CHANGED
@@ -3,8 +3,10 @@ Basic usage
3
3
 
4
4
  require 'rubygems'
5
5
  require 'amazon_product_advertising_api'
6
- # Setup your API key - in an initializer or something like that
6
+
7
+ # Setup your API keys - in an initializer or something like that
7
8
  AmazonProductAdvertisingApi::Base.access_key_id = "<insert api key here>"
9
+ AmazonProductAdvertisingApi::Base.secret_access_key = "<insert secret access key here>"
8
10
 
9
11
  # Setup Associates IDs for whichever regions you're selling to
10
12
  AmazonProductAdvertisingApi::Base.associate_ids.uk = "<insert UK Associate ID here>"
data/README.rdoc CHANGED
@@ -77,7 +77,6 @@ intended rules.
77
77
  = TODO
78
78
  - Implement the rest of the Operations (Cart*, Customer*, Help, List*, Seller*,
79
79
  Tag*, Transaction* and Vehicle*).
80
- - Implement HMAC before the authentication requirement kicks in in August 2009.
81
80
  - Implement batch and multiple operation requests, abstracted away from the
82
81
  user within the dsl.
83
82
  - Some sort of internal caching mechanism.
@@ -88,8 +87,8 @@ intended rules.
88
87
  = Obtaining
89
88
  The main repository is at github but there is also a rubyforge project.
90
89
 
91
- https://github.com/completelynovel/amazon-product-advertising-api/tree
92
- http://amazon-pa-api.rubyforge.org/
90
+ - https://github.com/completelynovel/amazon-product-advertising-api/tree
91
+ - http://amazon-pa-api.rubyforge.org/
93
92
 
94
93
 
95
94
  = Credits
data/Rakefile CHANGED
@@ -14,12 +14,14 @@ end
14
14
  begin
15
15
  require 'jeweler'
16
16
  Jeweler::Tasks.new do |gemspec|
17
- gemspec.name = "amazon-product-advertising-api"
18
- gemspec.summary = "A nice rubyish interface to the Amazon Product Advertising API."
19
- gemspec.email = "jon@completelynovel.com"
20
- gemspec.homepage = "http://github.com/completelynovel/amazon-product-advertising-api"
17
+ gemspec.name = "amazon-product-advertising-api"
18
+ gemspec.summary = "A nice rubyish interface to the Amazon Product Advertising API."
19
+ gemspec.email = "jon@completelynovel.com"
20
+ gemspec.homepage = "http://github.com/completelynovel/amazon-product-advertising-api"
21
21
  gemspec.description = "A nice rubyish interface to the Amazon Product Advertising API, formerly known as the Associates Web Service and before that the Amazon E-Commerce Service."
22
- gemspec.authors = ["Jon Gilbraith"]
22
+ gemspec.authors = ["Jon Gilbraith"]
23
+ gemspec.add_dependency("hpricot")
24
+ gemspec.add_dependency("ruby-hmac")
23
25
  end
24
26
  rescue LoadError
25
27
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{amazon-product-advertising-api}
5
- s.version = "0.1.0"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Jon Gilbraith"]
9
- s.date = %q{2009-07-06}
9
+ s.date = %q{2009-07-30}
10
10
  s.description = %q{A nice rubyish interface to the Amazon Product Advertising API, formerly known as the Associates Web Service and before that the Amazon E-Commerce Service.}
11
11
  s.email = %q{jon@completelynovel.com}
12
12
  s.extra_rdoc_files = [
@@ -40,8 +40,14 @@ Gem::Specification.new do |s|
40
40
  s.specification_version = 2
41
41
 
42
42
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
43
+ s.add_runtime_dependency(%q<hpricot>, [">= 0"])
44
+ s.add_runtime_dependency(%q<ruby-hmac>, [">= 0"])
43
45
  else
46
+ s.add_dependency(%q<hpricot>, [">= 0"])
47
+ s.add_dependency(%q<ruby-hmac>, [">= 0"])
44
48
  end
45
49
  else
50
+ s.add_dependency(%q<hpricot>, [">= 0"])
51
+ s.add_dependency(%q<ruby-hmac>, [">= 0"])
46
52
  end
47
53
  end
@@ -1,8 +1,8 @@
1
1
  module AmazonProductAdvertisingApi #:nodoc:
2
2
 
3
3
  # This is the main base class where you define your config data. Setup like so:
4
- # AmazonProductAdvertisingApi.base.access_key_id = <your Amazon AccessKeyId>
5
- # There is no support for the secret key yet, so it's just your access key for now.
4
+ # AmazonProductAdvertisingApi.base.access_key_id = <your Amazon AccessKeyId>
5
+ # AmazonProductAdvertisingApi.base.secret_access_key = <your Amazon SecretAccessKey>
6
6
  #
7
7
  # You also setup your Associates codes for different regions here (the right one is supplied)
8
8
  # based on what region you are requesting for.
@@ -11,6 +11,8 @@ module AmazonProductAdvertisingApi #:nodoc:
11
11
  class Base
12
12
 
13
13
  cattr_accessor :access_key_id
14
+
15
+ cattr_accessor :secret_access_key
14
16
 
15
17
  cattr_accessor :associate_ids
16
18
  @@associate_ids = Struct.new(:ca, :de, :fr, :jp, :uk, :us).new
@@ -41,13 +41,15 @@ module AmazonProductAdvertisingApi #:nodoc:
41
41
  attr_accessor :errors
42
42
 
43
43
  SERVICE_URLS = {
44
- :us => 'http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService',
45
- :uk => 'http://ecs.amazonaws.co.uk/onca/xml?Service=AWSECommerceService',
46
- :ca => 'http://ecs.amazonaws.ca/onca/xml?Service=AWSECommerceService',
47
- :de => 'http://ecs.amazonaws.de/onca/xml?Service=AWSECommerceService',
48
- :jp => 'http://ecs.amazonaws.jp/onca/xml?Service=AWSECommerceService',
49
- :fr => 'http://ecs.amazonaws.fr/onca/xml?Service=AWSECommerceService'
44
+ :us => 'http://ecs.amazonaws.com/onca/xml',
45
+ :uk => 'http://ecs.amazonaws.co.uk/onca/xml',
46
+ :ca => 'http://ecs.amazonaws.ca/onca/xml',
47
+ :de => 'http://ecs.amazonaws.de/onca/xml',
48
+ :jp => 'http://ecs.amazonaws.jp/onca/xml',
49
+ :fr => 'http://ecs.amazonaws.fr/onca/xml'
50
50
  }
51
+
52
+ API_VERSION = "2009-01-06"
51
53
 
52
54
  def initialize
53
55
  self.response = AmazonProductAdvertisingApi::Operations::Base::Element.new
@@ -57,16 +59,31 @@ module AmazonProductAdvertisingApi #:nodoc:
57
59
  # This takes care of building request, performing it, storing the results, checking for errors then parsing the data (if the request was valid).
58
60
  def query_amazon(params)
59
61
  request_params = {}
60
- request_params["AWSAccessKeyId"] = AmazonProductAdvertisingApi::Base.access_key_id
61
- request_params["Operation"] = self.operation
62
- request_params["AssociateTag"] = AmazonProductAdvertisingApi::Base.associate_ids.send(self.region) unless AmazonProductAdvertisingApi::Base.associate_ids.send(self.region).nil?
62
+ request_params["Service"] = "AWSECommerceService"
63
+ request_params["SignatureVersion"] = 2
64
+ request_params["SignatureMethod"] = "HmacSHA256"
65
+ request_params["Timestamp"] = Time.now.gmtime.iso8601
66
+ request_params["AWSAccessKeyId"] = AmazonProductAdvertisingApi::Base.access_key_id
67
+ request_params["Operation"] = self.operation
68
+ request_params["AssociateTag"] = AmazonProductAdvertisingApi::Base.associate_ids.send(self.region) unless AmazonProductAdvertisingApi::Base.associate_ids.send(self.region).nil?
69
+ request_params["Version"] = API_VERSION
63
70
  request_params.merge!(params)
71
+
72
+ # Process all params - make sure they're all strings, camelize and escape (where appropriate)
73
+ request_params = request_params.collect { |var, val| [var.to_s.camelize, val.to_s] }
74
+ request_params = request_params.collect { |var, val| [var, CGI::escape(val).gsub('+', '%20')] }
64
75
 
65
- self.request_uri = "#{SERVICE_URLS[self.region]}&#{request_params.collect { |var, val| var.to_s.camelize + "=" + val.to_s }.join("&")}"
66
- self.request_uri = URI.parse(URI.escape(self.request_uri))
67
-
76
+ # Assemble into a full request string
77
+ unsigned_uri = URI.parse("#{SERVICE_URLS[self.region]}?#{request_params.sort { |a, b| a[0] <=> b[0] }.collect { |var, val| var + "=" + val }.join("&")}")
78
+
79
+ # Generate hmac
80
+ hmac = HMAC::SHA256.new(AmazonProductAdvertisingApi::Base.secret_access_key)
81
+ hmac.update("GET\n#{unsigned_uri.host}\n#{unsigned_uri.path}\n#{unsigned_uri.query}")
82
+
83
+ self.request_uri = URI.parse("#{unsigned_uri}&Signature=#{Base64.encode64(hmac.digest).chomp}")
84
+
68
85
  result = Net::HTTP::get_response(self.request_uri)
69
- raise("Error connecting to Amazon") if !result.kind_of?(Net::HTTPSuccess)
86
+ raise("Error connecting to Amazon - #{result.to_s}") if !result.kind_of?(Net::HTTPSuccess)
70
87
 
71
88
  # Store away the raw data for debugging or if more direct access is required
72
89
  self.raw_data = result.body
@@ -1,67 +1,67 @@
1
1
  module AmazonProductAdvertisingApi #:nodoc:
2
-
3
- # Some extensions to the Class class.
4
- class Class
2
+ module CoreExtensions
3
+ module Class
5
4
 
6
- # Pleasant syntax for Class attribute readers.
7
- def cattr_reader(sym)
8
- class_eval(<<-EOS, __FILE__, __LINE__)
9
- unless defined? @@#{sym} # unless defined? @@hair_colors
10
- @@#{sym} = nil # @@hair_colors = nil
11
- end # end
12
- #
13
- def self.#{sym} # def self.hair_colors
14
- @@#{sym} # @@hair_colors
15
- end # end
16
- #
17
- def #{sym} # def hair_colors
18
- @@#{sym} # @@hair_colors
19
- end # end
20
- EOS
21
- end
5
+ # Pleasant syntax for Class attribute readers.
6
+ def cattr_reader(sym)
7
+ class_eval(<<-EOS, __FILE__, __LINE__)
8
+ unless defined? @@#{sym} # unless defined? @@hair_colors
9
+ @@#{sym} = nil # @@hair_colors = nil
10
+ end # end
11
+ #
12
+ def self.#{sym} # def self.hair_colors
13
+ @@#{sym} # @@hair_colors
14
+ end # end
15
+ #
16
+ def #{sym} # def hair_colors
17
+ @@#{sym} # @@hair_colors
18
+ end # end
19
+ EOS
20
+ end
22
21
 
23
- # Pleasant syntax for Class attribute writers.
24
- def cattr_writer(sym)
25
- class_eval(<<-EOS, __FILE__, __LINE__)
26
- unless defined? @@#{sym} # unless defined? @@hair_colors
27
- @@#{sym} = nil # @@hair_colors = nil
28
- end # end
29
- #
30
- def self.#{sym}=(obj) # def self.hair_colors=(obj)
31
- @@#{sym} = obj # @@hair_colors = obj
32
- end # end
33
- EOS
34
- end
22
+ # Pleasant syntax for Class attribute writers.
23
+ def cattr_writer(sym)
24
+ class_eval(<<-EOS, __FILE__, __LINE__)
25
+ unless defined? @@#{sym} # unless defined? @@hair_colors
26
+ @@#{sym} = nil # @@hair_colors = nil
27
+ end # end
28
+ #
29
+ def self.#{sym}=(obj) # def self.hair_colors=(obj)
30
+ @@#{sym} = obj # @@hair_colors = obj
31
+ end # end
32
+ EOS
33
+ end
34
+
35
+ # Pleasant syntax for Class attribute accessors.
36
+ def cattr_accessor(sym)
37
+ cattr_reader(sym)
38
+ cattr_writer(sym)
39
+ end
35
40
 
36
- # Pleasant syntax for Class attribute accessors.
37
- def cattr_accessor(sym)
38
- cattr_reader(sym)
39
- cattr_writer(sym)
40
41
  end
41
42
 
42
- end
43
+ # Some extensions to the String class.
44
+ module String
43
45
 
44
- # Some extensions to the String class.
45
- class String
46
+ # Converts strings from under_score format to CamelCase
47
+ def camelize(first_letter_in_uppercase = true)
48
+ if first_letter_in_uppercase
49
+ self.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
50
+ else
51
+ self.first + camelize(self)[1..-1]
52
+ end
53
+ end
46
54
 
47
- # Converts strings from under_score format to CamelCase
48
- def camelize(first_letter_in_uppercase = true)
49
- if first_letter_in_uppercase
50
- self.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
51
- else
52
- self.first + camelize(self)[1..-1]
55
+ # Converts strings from CamelCase format to under_score.
56
+ def underscore
57
+ self.to_s.gsub(/::/, '/').
58
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
59
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
60
+ tr("-", "_").
61
+ downcase
53
62
  end
54
- end
55
63
 
56
- # Converts strings from CamelCase format to under_score.
57
- def underscore
58
- self.to_s.gsub(/::/, '/').
59
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
60
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
61
- tr("-", "_").
62
- downcase
63
64
  end
64
-
65
- end
66
65
 
66
+ end
67
67
  end
@@ -1,7 +1,16 @@
1
1
  require 'net/http'
2
+ require 'cgi'
2
3
  require 'hpricot'
4
+ require 'time'
5
+ require 'hmac'
6
+ require 'hmac-sha2'
7
+ require 'base64'
3
8
 
4
9
  require 'amazon_product_advertising_api/support'
10
+
11
+ Class.send(:include, AmazonProductAdvertisingApi::CoreExtensions::Class)
12
+ String.send(:include, AmazonProductAdvertisingApi::CoreExtensions::String)
13
+
5
14
  require 'amazon_product_advertising_api/base'
6
15
  require 'amazon_product_advertising_api/response_elements'
7
16
  require 'amazon_product_advertising_api/operations/base'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: completelynovel-amazon-product-advertising-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Gilbraith
@@ -9,10 +9,29 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-06 00:00:00 -07:00
12
+ date: 2009-07-30 00:00:00 -07:00
13
13
  default_executable:
14
- dependencies: []
15
-
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: ruby-hmac
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
16
35
  description: A nice rubyish interface to the Amazon Product Advertising API, formerly known as the Associates Web Service and before that the Amazon E-Commerce Service.
17
36
  email: jon@completelynovel.com
18
37
  executables: []
@@ -38,6 +57,7 @@ files:
38
57
  - lib/amazon_product_advertising_api/support.rb
39
58
  has_rdoc: true
40
59
  homepage: http://github.com/completelynovel/amazon-product-advertising-api
60
+ licenses:
41
61
  post_install_message:
42
62
  rdoc_options:
43
63
  - --charset=UTF-8
@@ -58,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
78
  requirements: []
59
79
 
60
80
  rubyforge_project:
61
- rubygems_version: 1.2.0
81
+ rubygems_version: 1.3.5
62
82
  signing_key:
63
83
  specification_version: 2
64
84
  summary: A nice rubyish interface to the Amazon Product Advertising API.