impact_radius_api 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c4063f4161518d14f0989752c999951978ce43c3
4
+ data.tar.gz: f0ce5ee84eadc3b841333ab37e469aacd5734466
5
+ SHA512:
6
+ metadata.gz: d385f07828e0826f173f50ced63ce5c8de7cf361b24023bde9e05f7cf4238e0a1f583e2f3cc69589b881a145e0fe69fee384abc631bd812c332851e996311bf2
7
+ data.tar.gz: 54be1d72ff0a6218fde05a42712c19af17e5825877bd6ac96a00e6d8a08bc9d0835fe2d80bfab0721bc22fc2d6fd619f0bb91ad0b7aed7b7e125df51473e9a96
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in impact_radius_api.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Kirk Jarvis
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # ImpactRadiusApi
2
+
3
+ Ruby wrapper for [Impact Radius API](http://dev.impactradius.com/display/api/Home). Only [Media Partner Resources](http://dev.impactradius.com/display/api/Media+Partner+Resources) is curently supported.
4
+
5
+ If you need services that are not yet supported, feel free to contribute. For questions or bugs please create an issue.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'impact_radius_api'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install impact_radius_api
22
+
23
+ ## Configuration
24
+ This gem is designed to support [Media Partner Resources](http://dev.impactradius.com/display/api/Media+Partner+Resources).
25
+ All requests to the Impact Radius REST API require you to use HTTP Basic Authentication to convey your identity.
26
+
27
+ The username is your AccountSid (a 34 character string identifying your API account, starting with the letters "IR"). The password is your authentication token (AuthToken). These values are available on the Technical Settings page of your account.
28
+
29
+ To start using the gem, you need to set up the AccountSid (username) and authentication token first. If you use Ruby on Rails, the API key can be set in a configuration file (i.e. `app/config/initializers/impact_radius.rb`), otherwise just set it in your script.
30
+
31
+ ```ruby
32
+ require "impact_radius_api" # no need for RoR :account_sid, :auth_token,
33
+ ImpactRadiusAPI.auth_token = ENV["IR_AUTH_TOKEN"]
34
+ ImpactRadiusAPI.account_sid = ENV["IR_ACCOUNT_SID"]
35
+ ```
36
+ ##Configuration Example
37
+ This applys to Ruby on Rails. Create ```app/config/initializer/impact_radius_api.rb``` and add the following:
38
+ ```ruby
39
+ ImpactRadiusAPI.auth_token = ENV["IR_AUTH_TOKEN"]
40
+ ImpactRadiusAPI.account_sid = ENV["IR_ACCOUNT_SID"]
41
+ ```
42
+ ##Usage
43
+ ###Media Partner Resources Ads
44
+ Will return all Banner and Text Link ads. See Impact Radius API Documentation [Ads](http://dev.impactradius.com/display/api/Campaign+Ads)
45
+ ```ruby
46
+ require "impact_radius_api" #not needed for RoR
47
+ ImpactRadiusAPI.auth_token = ENV["IR_AUTH_TOKEN"] #can be in app/config/initializer/impact_radius_api.rb of RoR
48
+ ImpactRadiusAPI.account_sid = ENV["IR_ACCOUNT_SID"] #can be in app/config/initializer/impact_radius_api.rb of RoR
49
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
50
+ options = {
51
+ type: "BANNER" #for only banner ads default is both banner and text link.
52
+ }
53
+ response = mediapartners.get("Ads", options)
54
+ response.data.each do |ad|
55
+ puts "Name: #{ad.Name}"
56
+ puts "Description: #{ad.Description}"
57
+ puts "Link: #{ad.TrackingLink}"
58
+ end
59
+ ```
60
+ If there are multiple pages, retrieve all the pages by using the ```all``` method:
61
+ ```ruby
62
+ response.all.each do |ad|
63
+ # Do stuff
64
+ end
65
+ ```
66
+ ###Media Partner Resources Product
67
+ Will return Products. See Impact Radius API Documentation [Products](http://dev.impactradius.com/display/api/Product+Data+System+Media+Partner+Resources)
68
+ Catalogs and ItemSearch will only work right now. ItemSearch is only for Retail.
69
+ ```ruby
70
+ require "impact_radius_api" #not needed for RoR
71
+ ImpactRadiusAPI.auth_token = ENV["IR_AUTH_TOKEN"] #can be in app/config/initializer/impact_radius_api.rb of RoR
72
+ ImpactRadiusAPI.account_sid = ENV["IR_ACCOUNT_SID"] #can be in app/config/initializer/impact_radius_api.rb of RoR
73
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
74
+ options = {
75
+ Query=Color:"Red"
76
+ }
77
+ response = mediapartners.get("Products/ItemSearch", options)
78
+ response.data.each do |item|
79
+ puts "Name: #{item.Name}"
80
+ puts "Description: #{item.Description}"
81
+ puts "Link: #{item.TrackingLink}"
82
+ end
83
+ ```
84
+
85
+ If there are multiple pages, retrieve all the pages by using the ```all``` method:
86
+ ```ruby
87
+ response.all.each do |item|
88
+ # Do stuff
89
+ end
90
+ ```
91
+
92
+
93
+ ## Contributing
94
+
95
+ 1. Fork it ( https://github.com/[my-github-username]/impact_radius_api/fork )
96
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
97
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
98
+ 4. Push to the branch (`git push origin my-new-feature`)
99
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,32 @@
1
+ #coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'impact_radius_api/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "impact_radius_api"
8
+ spec.version = ImpactRadiusAPI::VERSION
9
+ spec.authors = ["Kirk Jarvis"]
10
+ spec.email = ["zuuzlo@yahoo.com"]
11
+ spec.summary = %q{Ruby wrapper for Impact Radius API}
12
+ spec.description = %q{Ruby wrapper for Impact Radius API (http://dev.impactradius.com/display/api/Home). Media Partner Resources (http://dev.impactradius.com/display/api/Media+Partner+Resources) and part of (http://dev.impactradius.com/display/api/Product+Data+System+Media+Partner+Resources) is curently supported.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "webmock", '~> 1.20.0'
24
+ spec.add_development_dependency "rspec", "~> 3.1.0"
25
+ spec.add_development_dependency "pry"
26
+
27
+ spec.add_dependency "addressable", "~> 2.3", ">= 2.3.6"
28
+ spec.add_dependency "htmlentities", "~> 4.3", ">= 4.3.2"
29
+ spec.add_dependency "httparty", "~> 0.13"
30
+ spec.add_dependency "json", "~> 1.8", ">= 1.8.1"
31
+ spec.add_dependency "recursive-open-struct", "~> 0.5", ">= 0.5.0"
32
+ end
@@ -0,0 +1,34 @@
1
+ require "impact_radius_api/version"
2
+ require "addressable/uri"
3
+ require "cgi"
4
+ require "htmlentities"
5
+ require "httparty"
6
+ require "recursive_open_struct"
7
+ require "uri"
8
+
9
+ require "impact_radius_api/api_resource"
10
+ require "impact_radius_api/api_response"
11
+ require "impact_radius_api/version"
12
+ require "impact_radius_api/mediapartners"
13
+
14
+ require "impact_radius_api/errors/error"
15
+ require "impact_radius_api/errors/authentication_error"
16
+ require "impact_radius_api/errors/argument_error"
17
+ require "impact_radius_api/errors/not_implemented_error"
18
+ require "impact_radius_api/errors/invalid_request_error"
19
+
20
+ module ImpactRadiusAPI
21
+ @api_base_uri = "api.impactradius.com"
22
+ @api_timeout = 30
23
+
24
+ class << self
25
+ attr_accessor :api_base_uri, :account_sid, :auth_token, :api_version
26
+ attr_reader :api_timeout
27
+ end
28
+
29
+ def self.api_timeout=(timeout)
30
+ raise ArgumentError, "Timeout must be a Fixnum; got #{timeout.class} instead" unless timeout.is_a? Fixnum
31
+ raise ArgumentError, "Timeout must be > 0; got #{timeout} instead" unless timeout > 0
32
+ @api_timeout = timeout
33
+ end
34
+ end
@@ -0,0 +1,90 @@
1
+ module ImpactRadiusAPI
2
+ class APIResource
3
+ include HTTParty
4
+
5
+ def class_name
6
+ self.class.name.split('::')[-1]
7
+ end
8
+
9
+ def base_path
10
+ if self.class_name == "APIResource"
11
+ raise NotImplementedError.new("APIResource is an abstract class. You should perform actions on its subclasses (i.e. Publisher)")
12
+ end
13
+ "/#{CGI.escape(class_name)}/"
14
+ end
15
+
16
+ def get(api_resource, params = {})
17
+ @resource ||= self.xml_field(api_resource)
18
+ unless auth_token ||= ImpactRadiusAPI.auth_token
19
+ raise AuthenticationError.new(
20
+ "No authentication token (AuthToken) provided. Set your API key using 'ImpactRadiusAPI.auth_token = <API-KEY>'. " +
21
+ "You can retrieve your authentication token (AuthToken) from the Impact Radius web interface. " +
22
+ "See http://dev.impactradius.com/display/api/Getting+Started for details."
23
+ )
24
+ end
25
+ if auth_token =~ /\s/
26
+ raise AuthenticationError.new(
27
+ "Your authentication token (AuthToken) looks invalid. " +
28
+ "Double-check your authentication token (AuthToken) at http://dev.impactradius.com/display/api/Getting+Started"
29
+ )
30
+ end
31
+
32
+ unless account_sid ||= ImpactRadiusAPI.account_sid
33
+ raise AuthenticationError.new(
34
+ "No account_sid (AccountSid) provided. Set your account_sid (AccountSid) using 'ImpactRadiusAPI.account_sid = <AccountSid>'. " +
35
+ "You can retrieve your account_sid (AccountSid) from the Impact Radius web interface. " +
36
+ "See http://dev.impactradius.com/display/api/Getting+Started for details."
37
+ )
38
+ end
39
+
40
+ if account_sid =~ /\s/ || account_sid.length != 34 || account_sid[0..1] != "IR"
41
+ raise AuthenticationError.new(
42
+ "Your account_sid (AccountSid) looks invalid. " +
43
+ "Double-check your account_sid (AccountSid) at http://dev.impactradius.com/display/api/Getting+Started"
44
+ )
45
+ end
46
+
47
+ raise ArgumentError, "Params must be a Hash; got #{params.class} instead" unless params.is_a? Hash
48
+
49
+ #resource_url = ImpactRadiusAPI.api_base_url + base_path + api_resource
50
+ resource_url = "https://" + account_sid + ":" + auth_token +"@" + pre_uri + ImpactRadiusAPI.api_base_uri + base_path + account_sid + "/" + api_resource
51
+ request(resource_url, params)
52
+ end
53
+
54
+ def request(resource_url, params = {})
55
+ timeout = ImpactRadiusAPI.api_timeout
56
+
57
+ @resource ||= self.xml_field(resource_url.match(/\/[a-z]+(\?|\z)/i)[0].gsub("/","").gsub("?",""))
58
+
59
+ begin
60
+ response = self.class.get(resource_url, query: params, timeout: timeout)
61
+ rescue Timeout::Error
62
+ raise ConnectionError.new("Timeout error (#{timeout}s)")
63
+ end
64
+ process(response)
65
+ end
66
+
67
+ private
68
+
69
+ def process(response)
70
+ case response.code
71
+ when 200, 201, 204
72
+ APIResponse.new(response, @resource)
73
+ when 400, 404
74
+ raise InvalidRequestError.new(response["ImpactRadiusResponse"]["Message"], response.code)
75
+ when 401
76
+ raise AuthenticationError.new(response["ImpactRadiusResponse"]["Message"], response.code)
77
+ else
78
+ raise Error.new(response["ImpactRadiusResponse"]["Message"], response.code)
79
+ end
80
+ end
81
+
82
+ def pre_uri
83
+ if %w(Ads PromotionalAds ActionInquiries Campaigns Acitons).include? @resource
84
+ ""
85
+ else
86
+ "product."
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,40 @@
1
+ module ImpactRadiusAPI
2
+ class APIResponse
3
+ attr_reader :data, :request, :page, :num_pages, :page_size
4
+
5
+ def initialize(response, resource)
6
+ @request = response.request
7
+ result = response["ImpactRadiusResponse"]
8
+ @page = result[resource]["page"].to_i
9
+ @num_pages = result[resource]["numpages"].to_i
10
+ @page_size = result[resource]["pagesize"]
11
+ require 'pry'; binding.pry
12
+ @data = parse(result[resource][resource[0..-2]])
13
+ end
14
+
15
+ def all
16
+ page = @page
17
+ num_pages = @num_pages
18
+
19
+ while num_pages > page
20
+ uri = Addressable::URI.parse(request.uri)
21
+ class_name = uri.path.match(/^\/[a-z]+\//i)[0].gsub("/","")
22
+ params = uri.query_values
23
+ params.merge!({ 'Page' => "#{page.to_i + 1}" })
24
+ next_page_response = ImpactRadiusAPI.const_get(class_name).new.request( uri.origin + uri.path, params )
25
+ page = next_page_response.page
26
+ @data += next_page_response.data
27
+ end
28
+ @data
29
+ end
30
+
31
+ private
32
+
33
+ def parse(raw_data)
34
+ data = []
35
+ data = [RecursiveOpenStruct.new(raw_data)] if raw_data.is_a?(Hash) # If we got exactly one result, put it in an array.
36
+ raw_data.each { |i| data << RecursiveOpenStruct.new(i) } if raw_data.is_a?(Array)
37
+ data
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,4 @@
1
+ module ImpactRadiusAPI
2
+ class ArgumentError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ImpactRadiusAPI
2
+ class AuthenticationError < Error
3
+ end
4
+ end
@@ -0,0 +1,15 @@
1
+ module ImpactRadiusAPI
2
+ class Error < StandardError
3
+ attr_reader :message, :status
4
+
5
+ def initialize(message = nil, status = nil)
6
+ @message = message
7
+ @status = status
8
+ end
9
+
10
+ def to_s
11
+ status_string = status.nil? ? "" : " (Status #{status})"
12
+ "#{message}#{status_string}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module ImpactRadiusAPI
2
+ class InvalidRequestError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ImpactRadiusAPI
2
+ class NotImplementedError < Error
3
+ end
4
+ end
@@ -0,0 +1,27 @@
1
+ module ImpactRadiusAPI
2
+ class Mediapartners < APIResource
3
+
4
+ def xml_field(resource)
5
+ case resource
6
+ when "Ads"
7
+ "Ads"
8
+ when "PromoAds"
9
+ "PromotionalAds"
10
+ when "ActionInquiries"
11
+ "ActionInquiries"
12
+ when "Campaigns"
13
+ "Campaigns"
14
+ when "Actions"
15
+ "Actions"
16
+ when "Catalogs"
17
+ "Catalogs"
18
+ when "Items"
19
+ "Items"
20
+ when "Catalogs/ItemSearch"
21
+ "Items"
22
+ else
23
+ raise InvalidRequestError.new("#{resource} is not a valid Media Partner Resources. Refer to: http://dev.impactradius.com/display/api/Media+Partner+Resources for valid Media Partner Resources.")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module ImpactRadiusAPI
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,834 @@
1
+ require 'spec_helper'
2
+
3
+ describe "impact_radius_api" do
4
+ describe ".api_timeout" do
5
+ context "time out integer and valid" do
6
+
7
+ it "valid time sets @api_timeout" do
8
+ ImpactRadiusAPI.api_timeout = 45
9
+ expect(ImpactRadiusAPI.api_timeout).to eq(45)
10
+ end
11
+ end
12
+
13
+ context "not valid timeout" do
14
+
15
+ it "rasie Argument error if api_timeout is a string" do
16
+ expect{ ImpactRadiusAPI.api_timeout = "45"}.to raise_error(ImpactRadiusAPI::ArgumentError,"Timeout must be a Fixnum; got String instead")
17
+ end
18
+
19
+ it "raise Argument error if api_timeout is below zero" do
20
+ expect{ ImpactRadiusAPI.api_timeout = 0 }.to raise_error(ImpactRadiusAPI::ArgumentError,"Timeout must be > 0; got 0 instead")
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "ImpactRadiusAPI::APIResource" do
26
+ describe ".class_name" do
27
+
28
+ it "should return class name" do
29
+ resource = ImpactRadiusAPI::Mediapartners.new
30
+ expect(resource.class_name).to eq("Mediapartners")
31
+ end
32
+ end
33
+
34
+ describe".base_path" do
35
+ it "should return error if APIResource" do
36
+ resource = ImpactRadiusAPI::APIResource.new
37
+ expect{resource.base_path}.to raise_error(ImpactRadiusAPI::NotImplementedError)
38
+ end
39
+
40
+ it "return base_path /Mediapartners/" do
41
+ resource = ImpactRadiusAPI::Mediapartners.new
42
+ expect(resource.base_path).to eq("/Mediapartners/")
43
+ end
44
+ end
45
+
46
+ describe ".get(api_resource, params)" do
47
+ context "no or invalid auth_token" do
48
+ it "raises authentication error if no auth_token" do
49
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
50
+ expect{ mediapartners.get("Ads") }.to raise_error(ImpactRadiusAPI::AuthenticationError)
51
+ end
52
+
53
+ it "raises authentication error if auth_token has spaces" do
54
+ ImpactRadiusAPI.auth_token = "xxxxx xxxxx"
55
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
56
+ expect{ mediapartners.get("Ads") }.to raise_error(ImpactRadiusAPI::AuthenticationError)
57
+ end
58
+
59
+ it "raises authentication error if no Account SID" do
60
+ ImpactRadiusAPI.auth_token = "xxxxxxxxxx"
61
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
62
+ expect{ mediapartners.get("Ads") }.to raise_error(ImpactRadiusAPI::AuthenticationError)
63
+ end
64
+
65
+ it "raises authentication error if account_sid (AccountSid) has space" do
66
+ ImpactRadiusAPI.auth_token = "xxxxxxxxxx"
67
+ ImpactRadiusAPI.account_sid = "IRxxx xxx"
68
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
69
+ expect{ mediapartners.get("Ads") }.to raise_error(ImpactRadiusAPI::AuthenticationError)
70
+ end
71
+
72
+ it "raises authentication error if Account SID doesn't start with IR" do
73
+ ImpactRadiusAPI.auth_token = "xxxxxxxxxx"
74
+ ImpactRadiusAPI.account_sid = "ERxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
75
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
76
+ expect{ mediapartners.get("Ads") }.to raise_error(ImpactRadiusAPI::AuthenticationError)
77
+ end
78
+
79
+ it "raises authentication error if Account SID doesn't have 34 chars" do
80
+ ImpactRadiusAPI.auth_token = "xxxxxxxxxx"
81
+ ImpactRadiusAPI.account_sid = "IRxxxxxx"
82
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
83
+ expect{ mediapartners.get("Ads") }.to raise_error(ImpactRadiusAPI::AuthenticationError)
84
+ end
85
+ end
86
+ context "params is not a Hash" do
87
+ it "raises ArgumentError if parms not a Hash" do
88
+ ImpactRadiusAPI.auth_token = "xxxxxxxxxx"
89
+ ImpactRadiusAPI.account_sid = "IRxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
90
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
91
+ expect{ mediapartners.get("Ads", "user") }.to raise_error(ImpactRadiusAPI::ArgumentError)
92
+ end
93
+ end
94
+
95
+ context "responce 200" do
96
+ before do
97
+ xml_response = <<-XML
98
+ <?xml version="1.0" encoding="UTF-8"?>
99
+ <ImpactRadiusResponse>
100
+ <Ads page="1" numpages="1" pagesize="100" total="2" start="0" end="1" uri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads" firstpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=100&amp;Page=1" previouspageuri="" nextpageuri="" lastpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=100&amp;Page=3">
101
+ <Ad>
102
+ <Id>163636</Id>
103
+ <Name>Free Shipping - 468x60</Name>
104
+ <Description/>
105
+ <CampaignId>2092</CampaignId>
106
+ <CampaignName>Target</CampaignName>
107
+ <Type>BANNER</Type>
108
+ <TrackingLink>http://goto.target.com/c/35691/163636/2092</TrackingLink>
109
+ <LandingPageUrl>http://www.target.com</LandingPageUrl>
110
+ <Code>&lt;a href="http://goto.target.com/c/35691/163636/2092"&gt; &lt;img src="http://adn.impactradius.com/display-ad/2092-163636" border="0" alt=""/&gt; &lt;/a&gt; &lt;img height="1" width="1" src="http://goto.target.com/i/35691/163636/2092" border="0" /&gt;</Code>
111
+ <IFrameCode>&lt;iframe src="http://adn.impactradius.com/gen-ad-code/35691/163636/2092/" scrolling="yes" frameborder="0" marginheight="0" marginwidth="0"&gt;&lt;/iframe&gt;</IFrameCode>
112
+ <Width>469</Width>
113
+ <Height>61</Height>
114
+ <CreativeUrl>https://adn-ssl.impactradius.com/display-ad/2092-163636</CreativeUrl>
115
+ <Tags/>
116
+ <AllowDeepLinking>true</AllowDeepLinking>
117
+ <MobileReady>false</MobileReady>
118
+ <Language>ENGLISH</Language>
119
+ <StartDate>2014-10-23T08:43:35-07:00</StartDate>
120
+ <EndDate/>
121
+ <Season/>
122
+ <TopSeller>false</TopSeller>
123
+ <DiscountCategory>FREESHIPPING</DiscountCategory>
124
+ <DiscountSubCategory>ENTIRESTORE</DiscountSubCategory>
125
+ <ProductName/>
126
+ <ProductImageUrl/>
127
+ <CouponCode/>
128
+ <DiscountAmount/>
129
+ <DiscountPercent/>
130
+ <BeforePrice/>
131
+ <AfterPrice/>
132
+ <MinimumPurchaseAmount/>
133
+ <SubjectLines/>
134
+ <FromAddresses/>
135
+ <UnsubscribeLink/>
136
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads/163636</Uri>
137
+ </Ad>
138
+ <Ad>
139
+ <Id>163635</Id>
140
+ <Name>Free Shipping - 320x50</Name>
141
+ <Description/>
142
+ <CampaignId>2092</CampaignId>
143
+ <CampaignName>Target</CampaignName>
144
+ <Type>BANNER</Type>
145
+ <TrackingLink>http://goto.target.com/c/35691/163635/2092</TrackingLink>
146
+ <LandingPageUrl>http://www.target.com</LandingPageUrl>
147
+ <Code>&lt;a href="http://goto.target.com/c/35691/163635/2092"&gt; &lt;img src="http://adn.impactradius.com/display-ad/2092-163635" border="0" alt=""/&gt; &lt;/a&gt; &lt;img height="1" width="1" src="http://goto.target.com/i/35691/163635/2092" border="0" /&gt;</Code>
148
+ <IFrameCode>&lt;iframe src="http://adn.impactradius.com/gen-ad-code/35691/163635/2092/" scrolling="yes" frameborder="0" marginheight="0" marginwidth="0"&gt;&lt;/iframe&gt;</IFrameCode>
149
+ <Width>321</Width>
150
+ <Height>51</Height>
151
+ <CreativeUrl>https://adn-ssl.impactradius.com/display-ad/2092-163635</CreativeUrl>
152
+ <Tags/>
153
+ <AllowDeepLinking>true</AllowDeepLinking>
154
+ <MobileReady>false</MobileReady>
155
+ <Language>ENGLISH</Language>
156
+ <StartDate>2014-10-23T08:43:35-07:00</StartDate>
157
+ <EndDate/>
158
+ <Season/>
159
+ <TopSeller>false</TopSeller>
160
+ <DiscountCategory>FREESHIPPING</DiscountCategory>
161
+ <DiscountSubCategory>ENTIRESTORE</DiscountSubCategory>
162
+ <ProductName/>
163
+ <ProductImageUrl/>
164
+ <CouponCode/>
165
+ <DiscountAmount/>
166
+ <DiscountPercent/>
167
+ <BeforePrice/>
168
+ <AfterPrice/>
169
+ <MinimumPurchaseAmount/>
170
+ <SubjectLines/>
171
+ <FromAddresses/>
172
+ <UnsubscribeLink/>
173
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads/163635</Uri>
174
+ </Ad>
175
+ </Ads>
176
+ </ImpactRadiusResponse>
177
+ XML
178
+ stub_request(
179
+ :get,
180
+ "https://IRkXujcbpSTF35691nPwrFCQsbVBwamUD1:CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm@api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads"
181
+ ).
182
+ to_return(
183
+ status: 200,
184
+ body: xml_response,
185
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
186
+ )
187
+ end
188
+
189
+ it "test to see url" do
190
+ ImpactRadiusAPI.auth_token = "CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm"
191
+ ImpactRadiusAPI.account_sid = "IRkXujcbpSTF35691nPwrFCQsbVBwamUD1"
192
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
193
+ response = mediapartners.get("Ads")
194
+ expect(response.data.first.Id).to eq("163636")
195
+ end
196
+ end
197
+
198
+ context "all response 200" do
199
+ before do
200
+ xml_response1 = <<-XML
201
+ <?xml version="1.0" encoding="UTF-8"?>
202
+ <ImpactRadiusResponse>
203
+ <Ads page="1" numpages="3" pagesize="2" total="253" start="0" end="1" uri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2" firstpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=1" previouspageuri="" nextpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=2" lastpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=127">
204
+ <Ad>
205
+ <Id>164487</Id>
206
+
207
+ </Ad>
208
+ <Ad>
209
+ <Id>164486</Id>
210
+
211
+ </Ad>
212
+ </Ads>
213
+ </ImpactRadiusResponse>
214
+ XML
215
+ stub_request(
216
+ :get,
217
+ "https://IRkXujcbpSTF35691nPwrFCQsbVBwamUD1:CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm@api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2"
218
+ ).
219
+ to_return(
220
+ status: 200,
221
+ body: xml_response1,
222
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
223
+ )
224
+ xml_response2 = <<-XML
225
+ <?xml version="1.0" encoding="UTF-8"?>
226
+ <ImpactRadiusResponse>
227
+ <Ads page="2" numpages="3" pagesize="2" total="253" start="2" end="3" uri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=2" firstpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=1" previouspageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=1" nextpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=3" lastpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=127">
228
+ <Ad>
229
+ <Id>164485</Id>
230
+
231
+ </Ad>
232
+ <Ad>
233
+ <Id>164484</Id>
234
+
235
+ </Ad>
236
+ </Ads>
237
+ </ImpactRadiusResponse>
238
+
239
+ XML
240
+ stub_request(
241
+ :get,
242
+ "https://api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&Page=2"
243
+ ).
244
+ to_return(
245
+ status: 200,
246
+ body: xml_response2,
247
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
248
+ )
249
+ xml_response3 = <<-XML
250
+ <?xml version="1.0" encoding="UTF-8"?>
251
+ <ImpactRadiusResponse>
252
+ <Ads page="3" numpages="3" pagesize="2" total="253" start="4" end="5" uri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=3" firstpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=1" previouspageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&amp;Page=2" nextpageuri="" lastpageuri="">
253
+ <Ad>
254
+ <Id>164483</Id>
255
+
256
+ </Ad>
257
+ <Ad>
258
+ <Id>164481</Id>
259
+
260
+ </Ad>
261
+ </Ads>
262
+ </ImpactRadiusResponse>
263
+ XML
264
+ stub_request(
265
+ :get,
266
+ "https://api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads?PageSize=2&Page=3"
267
+ ).
268
+ to_return(
269
+ status: 200,
270
+ body: xml_response3,
271
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
272
+ )
273
+ ImpactRadiusAPI.auth_token = "CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm"
274
+ ImpactRadiusAPI.account_sid = "IRkXujcbpSTF35691nPwrFCQsbVBwamUD1"
275
+ end
276
+
277
+
278
+ let(:mediapartners) {ImpactRadiusAPI::Mediapartners.new}
279
+ let(:params) {{ "PageSize" => "2" }}
280
+ let(:response) {mediapartners.get("Ads", params)}
281
+
282
+ it "get right first ID" do
283
+ expect(response.all.first.Id).to eq("164487")
284
+ end
285
+
286
+ it "right last ID" do
287
+ expect(response.all.last.Id).to eq("164481")
288
+ end
289
+ end
290
+ context "promoads .all response 200" do
291
+ before do
292
+ xml_response1 = <<-XML
293
+ <?xml version="1.0" encoding="UTF-8"?>
294
+ <ImpactRadiusResponse>
295
+ <PromotionalAds page="1" numpages="3" pagesize="2" total="185" start="0" end="1" uri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?Pagesize=2" firstpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=1" previouspageuri="" nextpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=2" lastpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=93">
296
+ <PromotionalAd>
297
+ <Id>79094</Id>
298
+ <Status>ACTIVE</Status>
299
+ <PromoType>FREESHIPPING</PromoType>
300
+ <TrackingLink>http://goto.target.com/c/35691/79094/2092</TrackingLink>
301
+ <DiscountPercent/>
302
+ <DiscountMinPurchaseAmount>20.00</DiscountMinPurchaseAmount>
303
+ </PromotionalAd>
304
+ <PromotionalAd>
305
+ <Id>79095</Id>
306
+ <Status>ACTIVE</Status>
307
+ <PromoType>FREESHIPPING</PromoType>
308
+ <TrackingLink>http://goto.target.com/c/35691/79095/2092</TrackingLink>
309
+ <DiscountPercent/>
310
+ <DiscountMinPurchaseAmount>50.00</DiscountMinPurchaseAmount>
311
+ </PromotionalAd>
312
+ </PromotionalAds>
313
+ </ImpactRadiusResponse>
314
+ XML
315
+ stub_request(
316
+ :get,
317
+ "https://IRkXujcbpSTF35691nPwrFCQsbVBwamUD1:CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm@api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2"
318
+ ).
319
+ to_return(
320
+ status: 200,
321
+ body: xml_response1,
322
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
323
+ )
324
+ xml_response2 = <<-XML
325
+ <?xml version="1.0" encoding="UTF-8"?>
326
+ <ImpactRadiusResponse>
327
+ <PromotionalAds page="2" numpages="3" pagesize="2" total="185" start="0" end="1" uri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?Pagesize=2" firstpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=1" previouspageuri="" nextpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=3" lastpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=93">
328
+ <PromotionalAd>
329
+ <Id>79096</Id>
330
+ <Status>ACTIVE</Status>
331
+ <PromoType>FREESHIPPING</PromoType>
332
+ <TrackingLink>http://goto.target.com/c/35691/79096/2092</TrackingLink>
333
+ <DiscountPercent/>
334
+ <DiscountMinPurchaseAmount>20.00</DiscountMinPurchaseAmount>
335
+ </PromotionalAd>
336
+ <PromotionalAd>
337
+ <Id>79097</Id>
338
+ <Status>ACTIVE</Status>
339
+ <PromoType>DOLLAROFF</PromoType>
340
+ <TrackingLink>http://goto.target.com/c/35691/79097/2092</TrackingLink>
341
+ <DiscountPercent/>
342
+ <DiscountMinPurchaseAmount>150.00</DiscountMinPurchaseAmount>
343
+ </PromotionalAd>
344
+ </PromotionalAds>
345
+ </ImpactRadiusResponse>
346
+ XML
347
+ stub_request(
348
+ :get,
349
+ "https://api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?Page=2&PageSize=2"
350
+ ).
351
+ to_return(
352
+ status: 200,
353
+ body: xml_response2,
354
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
355
+ )
356
+
357
+ xml_response3 = <<-XML
358
+ <?xml version="1.0" encoding="UTF-8"?>
359
+ <ImpactRadiusResponse>
360
+ <PromotionalAds page="3" numpages="3" pagesize="2" total="185" start="0" end="1" uri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?Pagesize=2" firstpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=1" previouspageuri="" nextpageuri="" lastpageuri="//Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?PageSize=2&amp;Page=3">
361
+ <PromotionalAd>
362
+ <Id>79098</Id>
363
+ <Status>ACTIVE</Status>
364
+ <PromoType>FREESHIPPING</PromoType>
365
+ <TrackingLink>http://goto.target.com/c/35691/79096/2092</TrackingLink>
366
+ <DiscountPercent/>
367
+ <DiscountMinPurchaseAmount>20.00</DiscountMinPurchaseAmount>
368
+ </PromotionalAd>
369
+ <PromotionalAd>
370
+ <Id>79099</Id>
371
+ <Status>ACTIVE</Status>
372
+ <PromoType>DOLLAROFF</PromoType>
373
+ <TrackingLink>http://goto.target.com/c/35691/79099/2092</TrackingLink>
374
+ <DiscountPercent/>
375
+ <DiscountMinPurchaseAmount>125.00</DiscountMinPurchaseAmount>
376
+ </PromotionalAd>
377
+ </PromotionalAds>
378
+ </ImpactRadiusResponse>
379
+ XML
380
+ stub_request(
381
+ :get,
382
+ "https://api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/PromoAds?Page=3&PageSize=2"
383
+ ).
384
+ to_return(
385
+ status: 200,
386
+ body: xml_response3,
387
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
388
+ )
389
+ ImpactRadiusAPI.auth_token = "CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm"
390
+ ImpactRadiusAPI.account_sid = "IRkXujcbpSTF35691nPwrFCQsbVBwamUD1"
391
+ end
392
+
393
+ let(:mediapartners) {ImpactRadiusAPI::Mediapartners.new}
394
+ let(:params) {{ "PageSize" => "2" }}
395
+ let(:response) {mediapartners.get("PromoAds", params)}
396
+
397
+ it "get right first DiscountMinPurchaseAmount" do
398
+ expect(response.all.first.DiscountMinPurchaseAmount).to eq("20.00")
399
+ end
400
+
401
+ it "right last DiscountMinPurchaseAmount" do
402
+ expect(response.all.last.DiscountMinPurchaseAmount).to eq("125.00")
403
+ end
404
+ end
405
+
406
+ context "Products 200 responce" do
407
+ before do
408
+ xml_response = <<-XML
409
+ <?xml version="1.0" encoding="UTF-8"?>
410
+ <ImpactRadiusResponse>
411
+ <Items pagesize="100" uri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/ItemSearch?Query=Color:red" firstpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/ItemSearch?PageSize=100&amp;Query=Color%3Ared" previouspageuri="" nextpageuri="/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/ItemSearch?PageSize=100&amp;AfterId=g2wAAAABaANkACdkYmNvcmVAZGIzLmltcGFjdHJhZGl1czAwMi5jbG91ZGFudC5uZXRsAAAAAm4EAAAAAKBuBAD___-_amgCRkADn-8AAAAAYgAiv4Vq&amp;Query=Color%3Ared">
412
+ <Item>
413
+ <Id>product_530_21460447</Id>
414
+ <CatalogId>530</CatalogId>
415
+ <CampaignId>2092</CampaignId>
416
+ <CampaignName>Target</CampaignName>
417
+ <CatalogItemId>21460447</CatalogItemId>
418
+ <Name>Allura 3/8 CT. T.W. Simulated Ruby Heart Pendant Necklace in Sterling Silver, Women's, Red</Name>
419
+ <Description>Find Fine Jewelry Necklaces, Bracelets, Anklets at Target.com! Allura 3/8 CT. T.W. Simulated Ruby Heart Pendant Necklace in Sterling Silver Color: Red. Gender: Female. Age Group: Adult.</Description>
420
+ <MultiPack/>
421
+ <Bullets/>
422
+ <Labels/>
423
+ <Manufacturer>Allura</Manufacturer>
424
+ <Url>http://goto.target.com/c/35691/78775/2092?aadid=21460447&amp;u=http%3A%2F%2Fwww.target.com%2Fp%2Fallura-3-8-ct-t-w-simulated-ruby-heart-pendant-necklace-in-sterling-silver%2F-%2FA-21460447</Url>
425
+ <MobileUrl/>
426
+ <ImageUrl>http://target.scene7.com/is/image/Target/21460447?wid=1000&amp;hei=1000</ImageUrl>
427
+ <ProductBid/>
428
+ <AdditionalImageUrls/>
429
+ <CurrentPrice>29.99</CurrentPrice>
430
+ <OriginalPrice>29.99</OriginalPrice>
431
+ <Currency>USD</Currency>
432
+ <StockAvailability>InStock</StockAvailability>
433
+ <EstimatedShipDate/>
434
+ <LaunchDate/>
435
+ <ExpirationDate/>
436
+ <Gtin>075000598628</Gtin>
437
+ <GtinType/>
438
+ <Asin/>
439
+ <Mpn/>
440
+ <ShippingRate>0.0</ShippingRate>
441
+ <ShippingWeight>1.0</ShippingWeight>
442
+ <ShippingWeightUnit>lb</ShippingWeightUnit>
443
+ <ShippingLength>8.0</ShippingLength>
444
+ <ShippingWidth>5.0</ShippingWidth>
445
+ <ShippingHeight>2.0</ShippingHeight>
446
+ <ShippingLengthUnit>in</ShippingLengthUnit>
447
+ <ShippingLabel/>
448
+ <Category/>
449
+ <OriginalFormatCategory>Apparel &amp; Accessories &gt; Jewelry &gt; Necklaces</OriginalFormatCategory>
450
+ <OriginalFormatCategoryId/>
451
+ <ParentName/>
452
+ <ParentSku/>
453
+ <IsParent>false</IsParent>
454
+ <Colors>
455
+ <Color>Red</Color>
456
+ </Colors>
457
+ <Material/>
458
+ <Pattern/>
459
+ <Size/>
460
+ <SizeUnit/>
461
+ <Weight>1.0</Weight>
462
+ <WeightUnit>lb</WeightUnit>
463
+ <Condition>New</Condition>
464
+ <AgeGroup>Adult</AgeGroup>
465
+ <Gender>Female</Gender>
466
+ <Adult>false</Adult>
467
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/530/Items/product_530_21460447</Uri>
468
+ </Item>
469
+ <Item>
470
+ <Id>product_530_50320962</Id>
471
+ <CatalogId>530</CatalogId>
472
+ <CampaignId>2092</CampaignId>
473
+ <CampaignName>Target</CampaignName>
474
+ <CatalogItemId>50320962</CatalogItemId>
475
+ <Name>6ct Burgundy Shiny Finial Drilled Christmas Ornament Set, Red</Name>
476
+ <Description>Find Seasonal Holiday Decorations at Target.com! 8” Vickerman shiny finished finial ornament set of 6. These ornaments are a unique shape with a protective UV coating perfect for your decorating projects, whatever they may be. Color: Red.</Description>
477
+ <MultiPack/>
478
+ <Bullets/>
479
+ <Labels/>
480
+ <Manufacturer>Vickerman</Manufacturer>
481
+ <Url>http://goto.target.com/c/35691/78775/2092?aadid=50320962&amp;u=http%3A%2F%2Fwww.target.com%2Fp%2F6ct-burgundy-shiny-finial-drilled-christmas-ornament-set%2F-%2FA-50320962</Url>
482
+ <MobileUrl/>
483
+ <ImageUrl>http://target.scene7.com/is/image/Target/50320962?wid=1000&amp;hei=1000</ImageUrl>
484
+ <ProductBid/>
485
+ <AdditionalImageUrls/>
486
+ <CurrentPrice>40.74</CurrentPrice>
487
+ <OriginalPrice>40.74</OriginalPrice>
488
+ <Currency>USD</Currency>
489
+ <StockAvailability>InStock</StockAvailability>
490
+ <EstimatedShipDate/>
491
+ <LaunchDate/>
492
+ <ExpirationDate/>
493
+ <Gtin>734205385821</Gtin>
494
+ <GtinType/>
495
+ <Asin/>
496
+ <Mpn/>
497
+ <ShippingRate>0.0</ShippingRate>
498
+ <ShippingWeight>6.0</ShippingWeight>
499
+ <ShippingWeightUnit>lb</ShippingWeightUnit>
500
+ <ShippingLength>13.0</ShippingLength>
501
+ <ShippingWidth>9.0</ShippingWidth>
502
+ <ShippingHeight>9.0</ShippingHeight>
503
+ <ShippingLengthUnit>in</ShippingLengthUnit>
504
+ <ShippingLabel/>
505
+ <Category/>
506
+ <OriginalFormatCategory>Home &amp; Garden &gt; Decor &gt; Seasonal &amp; Holiday Decorations &gt; Holiday Ornaments</OriginalFormatCategory>
507
+ <OriginalFormatCategoryId/>
508
+ <ParentName/>
509
+ <ParentSku/>
510
+ <IsParent>false</IsParent>
511
+ <Colors>
512
+ <Color>Red</Color>
513
+ </Colors>
514
+ <Material/>
515
+ <Pattern/>
516
+ <Size/>
517
+ <SizeUnit/>
518
+ <Weight>6.0</Weight>
519
+ <WeightUnit>lb</WeightUnit>
520
+ <Condition>New</Condition>
521
+ <AgeGroup/>
522
+ <Gender/>
523
+ <Adult>false</Adult>
524
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/530/Items/product_530_50320962</Uri>
525
+ </Item>
526
+ <Item>
527
+ <Id>product_530_50302458</Id>
528
+ <CatalogId>530</CatalogId>
529
+ <CampaignId>2092</CampaignId>
530
+ <CampaignName>Target</CampaignName>
531
+ <CatalogItemId>50302458</CatalogItemId>
532
+ <Name>Scholastic Trait Crate, Kindergarten, Six Books, Learning Guide, CD, More, Red</Name>
533
+ <Description>Find Educational Kits and Learning Tools at Target.com! Scholastic Trait Crate, Kindergarten, Six Books, Learning Guide, CD, More Color: Red.</Description>
534
+ <MultiPack/>
535
+ <Bullets/>
536
+ <Labels/>
537
+ <Manufacturer>Scholastic</Manufacturer>
538
+ <Url>http://goto.target.com/c/35691/78775/2092?aadid=50302458&amp;u=http%3A%2F%2Fwww.target.com%2Fp%2Fscholastic-trait-crate-kindergarten-six-books-learning-guide-cd-more%2F-%2FA-50302458</Url>
539
+ <MobileUrl/>
540
+ <ImageUrl>http://target.scene7.com/is/image/Target/50302458?wid=1000&amp;hei=1000</ImageUrl>
541
+ <ProductBid/>
542
+ <AdditionalImageUrls/>
543
+ <CurrentPrice>114.99</CurrentPrice>
544
+ <OriginalPrice>114.99</OriginalPrice>
545
+ <Currency>USD</Currency>
546
+ <StockAvailability>InStock</StockAvailability>
547
+ <EstimatedShipDate/>
548
+ <LaunchDate/>
549
+ <ExpirationDate/>
550
+ <Gtin>078073074709</Gtin>
551
+ <GtinType/>
552
+ <Asin/>
553
+ <Mpn/>
554
+ <ShippingRate>0.0</ShippingRate>
555
+ <ShippingWeight>2.6</ShippingWeight>
556
+ <ShippingWeightUnit>lb</ShippingWeightUnit>
557
+ <ShippingLength>9.75</ShippingLength>
558
+ <ShippingWidth>13.5</ShippingWidth>
559
+ <ShippingHeight>5.25</ShippingHeight>
560
+ <ShippingLengthUnit>in</ShippingLengthUnit>
561
+ <ShippingLabel/>
562
+ <Category/>
563
+ <OriginalFormatCategory>Media &gt; Books</OriginalFormatCategory>
564
+ <OriginalFormatCategoryId/>
565
+ <ParentName/>
566
+ <ParentSku/>
567
+ <IsParent>false</IsParent>
568
+ <Colors>
569
+ <Color>Red</Color>
570
+ </Colors>
571
+ <Material/>
572
+ <Pattern/>
573
+ <Size/>
574
+ <SizeUnit/>
575
+ <Weight>2.6</Weight>
576
+ <WeightUnit>lb</WeightUnit>
577
+ <Condition>New</Condition>
578
+ <AgeGroup/>
579
+ <Gender/>
580
+ <Adult>false</Adult>
581
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/530/Items/product_530_50302458</Uri>
582
+ </Item>
583
+ <Item>
584
+ <Id>product_530_50304525</Id>
585
+ <CatalogId>530</CatalogId>
586
+ <CampaignId>2092</CampaignId>
587
+ <CampaignName>Target</CampaignName>
588
+ <CatalogItemId>50304525</CatalogItemId>
589
+ <Name>4ct Burgundy Assorted Finishes Christmas Ornament Set, Red</Name>
590
+ <Description>Find Seasonal Holiday Decorations at Target.com! 10” assorted finish Vickerman shatterproof ornaments come with 1 matte, 1 shiny, 1 glitter, and 1 sequin totaling 4 pieces. Shatterproof ornaments give you the look of real glass with the safety and reliability of plastic. These small ornaments are the perfect size for your decorating projects, whatever they may be. Color: Red.</Description>
591
+ <MultiPack/>
592
+ <Bullets/>
593
+ <Labels/>
594
+ <Manufacturer>Vickerman</Manufacturer>
595
+ <Url>http://goto.target.com/c/35691/78775/2092?aadid=50304525&amp;u=http%3A%2F%2Fwww.target.com%2Fp%2F4ct-burgundy-assorted-finishes-christmas-ornament-set%2F-%2FA-50304525</Url>
596
+ <MobileUrl/>
597
+ <ImageUrl>http://target.scene7.com/is/image/Target/50304525?wid=1000&amp;hei=1000</ImageUrl>
598
+ <ProductBid/>
599
+ <AdditionalImageUrls/>
600
+ <CurrentPrice>80.94</CurrentPrice>
601
+ <OriginalPrice>80.94</OriginalPrice>
602
+ <Currency>USD</Currency>
603
+ <StockAvailability>InStock</StockAvailability>
604
+ <EstimatedShipDate/>
605
+ <LaunchDate/>
606
+ <ExpirationDate/>
607
+ <Gtin>734205352731</Gtin>
608
+ <GtinType/>
609
+ <Asin/>
610
+ <Mpn/>
611
+ <ShippingRate>0.0</ShippingRate>
612
+ <ShippingWeight>5.0</ShippingWeight>
613
+ <ShippingWeightUnit>lb</ShippingWeightUnit>
614
+ <ShippingLength>21.0</ShippingLength>
615
+ <ShippingWidth>21.0</ShippingWidth>
616
+ <ShippingHeight>11.0</ShippingHeight>
617
+ <ShippingLengthUnit>in</ShippingLengthUnit>
618
+ <ShippingLabel/>
619
+ <Category/>
620
+ <OriginalFormatCategory>Home &amp; Garden &gt; Decor &gt; Seasonal &amp; Holiday Decorations &gt; Holiday Ornaments</OriginalFormatCategory>
621
+ <OriginalFormatCategoryId/>
622
+ <ParentName/>
623
+ <ParentSku/>
624
+ <IsParent>false</IsParent>
625
+ <Colors>
626
+ <Color>Red</Color>
627
+ </Colors>
628
+ <Material/>
629
+ <Pattern/>
630
+ <Size/>
631
+ <SizeUnit/>
632
+ <Weight>5.0</Weight>
633
+ <WeightUnit>lb</WeightUnit>
634
+ <Condition>New</Condition>
635
+ <AgeGroup/>
636
+ <Gender/>
637
+ <Adult>false</Adult>
638
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/530/Items/product_530_50304525</Uri>
639
+ </Item>
640
+ <Item>
641
+ <Id>product_530_16620059</Id>
642
+ <CatalogId>530</CatalogId>
643
+ <CampaignId>2092</CampaignId>
644
+ <CampaignName>Target</CampaignName>
645
+ <CatalogItemId>16620059</CatalogItemId>
646
+ <Name>Pantone Expressions 5501R Runner - Warm (2'7X10'), Red</Name>
647
+ <Description>Find Rugs, Mats and Grips at Target.com! Energetic mid-century abstract expressionists splashed paint onto canvas in surprising ways. A few decades later, those splashes convey genuine feeling with a powerful color message. Expressions by Oriental Weavers for Pantone Universe is a new cross-woven rug collection with the energy and style of those mid-century artists. Cutting-edge creative technologies create a striking interplay of texture and painterly color in contemporary patterns. The colors used are:16-1359 Orange Peel18-2133 Pink Flamb'e18-1761 Ski Patrol13-0752 Lemon Size: 2'7X10' Runner. Color: Red. Gender: Unisex.</Description>
648
+ <MultiPack/>
649
+ <Bullets/>
650
+ <Labels/>
651
+ <Manufacturer>Pantone Universe</Manufacturer>
652
+ <Url>http://goto.target.com/c/35691/78775/2092?aadid=16620059&amp;u=http%3A%2F%2Fwww.target.com%2Fp%2Fpantone-expressions-5501r-runner-warm-2-7-x10%2F-%2FA-16620059</Url>
653
+ <MobileUrl/>
654
+ <ImageUrl>http://target.scene7.com/is/image/Target/16620059?wid=1000&amp;hei=1000</ImageUrl>
655
+ <ProductBid/>
656
+ <AdditionalImageUrls/>
657
+ <CurrentPrice>199.0</CurrentPrice>
658
+ <OriginalPrice>199.0</OriginalPrice>
659
+ <Currency>USD</Currency>
660
+ <StockAvailability>InStock</StockAvailability>
661
+ <EstimatedShipDate/>
662
+ <LaunchDate/>
663
+ <ExpirationDate/>
664
+ <Gtin>748679378463</Gtin>
665
+ <GtinType/>
666
+ <Asin/>
667
+ <Mpn/>
668
+ <ShippingRate>0.0</ShippingRate>
669
+ <ShippingWeight>11.0</ShippingWeight>
670
+ <ShippingWeightUnit>lb</ShippingWeightUnit>
671
+ <ShippingLength>31.0</ShippingLength>
672
+ <ShippingWidth>9.0</ShippingWidth>
673
+ <ShippingHeight>9.0</ShippingHeight>
674
+ <ShippingLengthUnit>in</ShippingLengthUnit>
675
+ <ShippingLabel/>
676
+ <Category/>
677
+ <OriginalFormatCategory>Home &amp; Garden &gt; Decor &gt; Rugs</OriginalFormatCategory>
678
+ <OriginalFormatCategoryId/>
679
+ <ParentName/>
680
+ <ParentSku/>
681
+ <IsParent>false</IsParent>
682
+ <Colors>
683
+ <Color>Red</Color>
684
+ </Colors>
685
+ <Material/>
686
+ <Pattern/>
687
+ <Size>2'7X10' Runner</Size>
688
+ <SizeUnit/>
689
+ <Weight>11.0</Weight>
690
+ <WeightUnit>lb</WeightUnit>
691
+ <Condition>New</Condition>
692
+ <AgeGroup/>
693
+ <Gender>Unisex</Gender>
694
+ <Adult>false</Adult>
695
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/530/Items/product_530_16620059</Uri>
696
+ </Item>
697
+ <Item>
698
+ <Id>product_530_14771096</Id>
699
+ <CatalogId>530</CatalogId>
700
+ <CampaignId>2092</CampaignId>
701
+ <CampaignName>Target</CampaignName>
702
+ <CatalogItemId>14771096</CatalogItemId>
703
+ <Name>Rubbermaid 4 Pc. Premium Cansister Set, Red</Name>
704
+ <Description>Find Household Food or Beverage Storage Containers at Target.com! Rubbermaid 4 Pc. Premium Cansister Set Color: Red. Pattern: Solid.</Description>
705
+ <MultiPack/>
706
+ <Bullets/>
707
+ <Labels/>
708
+ <Manufacturer>Rubbermaid</Manufacturer>
709
+ <Url>http://goto.target.com/c/35691/78775/2092?aadid=14771096&amp;u=http%3A%2F%2Fwww.target.com%2Fp%2Frubbermaid-4-pc-premium-cansister-set%2F-%2FA-14771096</Url>
710
+ <MobileUrl/>
711
+ <ImageUrl>http://target.scene7.com/is/image/Target/14771096?wid=1000&amp;hei=1000</ImageUrl>
712
+ <ProductBid/>
713
+ <AdditionalImageUrls/>
714
+ <CurrentPrice>35.99</CurrentPrice>
715
+ <OriginalPrice>35.99</OriginalPrice>
716
+ <Currency>USD</Currency>
717
+ <StockAvailability>InStock</StockAvailability>
718
+ <EstimatedShipDate/>
719
+ <LaunchDate/>
720
+ <ExpirationDate/>
721
+ <Gtin>71691466499</Gtin>
722
+ <GtinType/>
723
+ <Asin/>
724
+ <Mpn/>
725
+ <ShippingRate>0.0</ShippingRate>
726
+ <ShippingWeight>4.63</ShippingWeight>
727
+ <ShippingWeightUnit>lb</ShippingWeightUnit>
728
+ <ShippingLength>9.75</ShippingLength>
729
+ <ShippingWidth>10.125</ShippingWidth>
730
+ <ShippingHeight>11.125</ShippingHeight>
731
+ <ShippingLengthUnit>in</ShippingLengthUnit>
732
+ <ShippingLabel/>
733
+ <Category/>
734
+ <OriginalFormatCategory>Home &amp; Garden &gt; Kitchen &amp; Dining &gt; Food Storage &gt; Food Storage Containers</OriginalFormatCategory>
735
+ <OriginalFormatCategoryId/>
736
+ <ParentName/>
737
+ <ParentSku/>
738
+ <IsParent>false</IsParent>
739
+ <Colors>
740
+ <Color>Red</Color>
741
+ </Colors>
742
+ <Material/>
743
+ <Pattern>Solid</Pattern>
744
+ <Size/>
745
+ <SizeUnit/>
746
+ <Weight>4.63</Weight>
747
+ <WeightUnit>lb</WeightUnit>
748
+ <Condition>New</Condition>
749
+ <AgeGroup/>
750
+ <Gender/>
751
+ <Adult>false</Adult>
752
+ <Uri>/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/530/Items/product_530_14771096</Uri>
753
+ </Item>
754
+ </Items>
755
+ </ImpactRadiusResponse>
756
+ XML
757
+
758
+ stub_request(
759
+ :get,
760
+ "https://IRkXujcbpSTF35691nPwrFCQsbVBwamUD1:CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm@product.api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Catalogs/ItemSearch?Query=Color:red"
761
+ ).
762
+ to_return(
763
+ status: 200,
764
+ body: xml_response,
765
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
766
+ )
767
+
768
+
769
+ ImpactRadiusAPI.auth_token = "CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm"
770
+ ImpactRadiusAPI.account_sid = "IRkXujcbpSTF35691nPwrFCQsbVBwamUD1"
771
+ end
772
+
773
+ let(:mediapartners) {ImpactRadiusAPI::Mediapartners.new}
774
+ let(:params) {{ "Query" => "Color:red" }}
775
+ let(:response) {mediapartners.get("Catalogs/ItemSearch", params)}
776
+
777
+ it "first item is correct" do
778
+ expect(response.all.first.Id).to eq("product_530_21460447")
779
+ end
780
+ end
781
+
782
+ context "404 response" do
783
+ before do
784
+ xml_response = <<-XML
785
+ <?xml version="1.0" encoding="UTF-8"?>
786
+ <ImpactRadiusResponse><Status>ERROR</Status><Message>The requested resource was not found</Message></ImpactRadiusResponse>
787
+ XML
788
+ stub_request(
789
+ :get,
790
+ "https://IRkXujcbpSTF35691nPwrFCQsbVBwamUD1:CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm@api.impactradius.com/Mediapartners/IRkXujcbpSTF35691nPwrFCQsbVBwamUD1/Ads"
791
+ ).
792
+ to_return(
793
+ status: 404,
794
+ body: xml_response,
795
+ headers: { "Content-type" => "text/xml; charset=UTF-8" }
796
+ )
797
+ ImpactRadiusAPI.auth_token = "CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm"
798
+ ImpactRadiusAPI.account_sid = "IRkXujcbpSTF35691nPwrFCQsbVBwamUD1"
799
+ end
800
+
801
+ it "raise invalid request error 404" do
802
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
803
+ expect{mediapartners.get("Ads")}.to raise_error(ImpactRadiusAPI::InvalidRequestError, "The requested resource was not found")
804
+ end
805
+ end
806
+ end
807
+ end
808
+ describe "Mediapartners" do
809
+ describe ".xml_field" do
810
+ before do
811
+ ImpactRadiusAPI.auth_token = "CEdwLRxstFyC2qLAi58MiYe6sqVKD7Dm"
812
+ ImpactRadiusAPI.account_sid = "IRkXujcbpSTF35691nPwrFCQsbVBwamUD1"
813
+ end
814
+ context "InvalidRequestError" do
815
+ it "raise InvalidRequestError if not a media partner resource" do
816
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
817
+ expect{mediapartners.xml_field("Other")}.to raise_error(ImpactRadiusAPI::InvalidRequestError)
818
+ end
819
+ end
820
+ context "valid resource" do
821
+ it "returns PromotionalAds for resource PromoAds" do
822
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
823
+ expect(mediapartners.xml_field("PromoAds")).to eq("PromotionalAds")
824
+ end
825
+ end
826
+ context "add valid resource" do
827
+ it "returns Catalogs/ItemSearch for ItemSearch" do
828
+ mediapartners = ImpactRadiusAPI::Mediapartners.new
829
+ expect(mediapartners.xml_field("Catalogs/ItemSearch")).to eq("Items")
830
+ end
831
+ end
832
+ end
833
+ end
834
+ end