zanoxrb 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -1
- data/README.md +6 -2
- data/Rakefile +6 -0
- data/lib/zanox/hashable.rb +43 -0
- data/lib/zanox/resources/adspace.rb +74 -0
- data/lib/zanox/resources/item.rb +39 -0
- data/lib/zanox/resources/product.rb +89 -0
- data/lib/zanox/resources/program_application.rb +58 -0
- data/lib/zanox/resources/shop.rb +113 -0
- data/lib/zanox/response.rb +1 -1
- data/lib/zanox/version.rb +1 -1
- data/lib/zanox.rb +9 -0
- data/specs/resources/product_spec.rb +100 -0
- data/specs/resources/shop_spec.rb +145 -0
- data/zanoxrb.gemspec +1 -0
- metadata +23 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2972b4fe3fec25d73833848f7585a732de4e7c5
|
4
|
+
data.tar.gz: ec85cc77504d167494692ba309c9bf1d1769e0a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b94269bfb5f10350e230fba309c2c9bc41bd4a87598ba7a0226ba339a958f05ba3af36ab2c74049bec552826dc2da3c4beb0ad2644ae51794e76ac133b51df23
|
7
|
+
data.tar.gz: 89a2f98563bc8b42579a66edda97297554fe9eb81584727f586638c5db8e88b3f7144904e70c740364e041e80da5aea4cdcec58ac35720ab2da4b562646a1882
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
zanoxrb (0.
|
4
|
+
zanoxrb (0.5)
|
5
5
|
httparty (~> 0.13)
|
6
|
+
ruby-try (~> 1.1)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
@@ -29,6 +30,7 @@ GEM
|
|
29
30
|
diff-lcs (>= 1.2.0, < 2.0)
|
30
31
|
rspec-support (~> 3.3.0)
|
31
32
|
rspec-support (3.3.0)
|
33
|
+
ruby-try (1.1.1)
|
32
34
|
|
33
35
|
PLATFORMS
|
34
36
|
ruby
|
@@ -38,3 +40,6 @@ DEPENDENCIES
|
|
38
40
|
rspec (~> 3.3)
|
39
41
|
rspec-collection_matchers (~> 1.1)
|
40
42
|
zanoxrb!
|
43
|
+
|
44
|
+
BUNDLED WITH
|
45
|
+
1.10.4
|
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
ZanoxRB [![Build Status](https://travis-ci.org/mozestudio/zanox-rb.svg)](https://travis-ci.org/mozestudio/zanox-rb)
|
2
2
|
=======
|
3
3
|
A Ruby wrapper for Zanox's RESTful APIs because all the current alternatives outta here are shit.
|
4
|
-
|
4
|
+
|
5
|
+
Currently it supports only `GET` requests (aka, read-only).
|
5
6
|
|
6
7
|
Install
|
7
8
|
=======
|
@@ -17,7 +18,10 @@ $ export ZANOX_SECRET_KEY=''
|
|
17
18
|
|
18
19
|
To make requests to the APIs, call `Zanox::API#request` passing the endpoint of the method you want to call and optionally a hash with one or more params (such as `q`, `date`, `programs`, etc.) based on the official documentation you can find [here](https://developer.zanox.com/web/guest/publisher-api-2011/).
|
19
20
|
|
20
|
-
Every call will return a native Ruby hash or an array reflecting the original documentation provided by Zanox
|
21
|
+
Every call will return a native Ruby hash or an array reflecting the original documentation provided by Zanox.
|
22
|
+
|
23
|
+
Alternatively you can use the native wrappers provided inside `resources/`.
|
24
|
+
They are a few and also they're under development, and if you need something complex probably they might be not the best choice, but for just reading and manipulate collections they're useful enough since there is no need to work on raw data.
|
21
25
|
|
22
26
|
Note also that the pagination in Zanox APIs is 0-indexed. For example, if you want to get the second page of the requested products list you have to pass `page: 1` to the optional params, otherwise you'll get, of course, the first page that actually is referrable as `page: 0`.
|
23
27
|
Consider using `Zanox::Response#next_page` and `Zanox::Response#previous_page` to navigate through the pages.
|
data/Rakefile
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are
|
5
|
+
# permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
8
|
+
# conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
11
|
+
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
|
13
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
14
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
15
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
16
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
17
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
18
|
+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
|
+
#
|
20
|
+
# The views and conclusions contained in the software and documentation are those of the
|
21
|
+
# authors and should not be interpreted as representing official policies, either expressed
|
22
|
+
# or implied, of Giovanni Capuano.
|
23
|
+
#++
|
24
|
+
|
25
|
+
module Zanox
|
26
|
+
module Hashable
|
27
|
+
def to_hash
|
28
|
+
attributes.each_with_object({}) do |attr, hash|
|
29
|
+
key = attr.to_s.delete('@')
|
30
|
+
hash[key] = attribute(attr)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def attributes
|
36
|
+
instance_variables
|
37
|
+
end
|
38
|
+
|
39
|
+
def attribute(attr)
|
40
|
+
instance_variable_get(attr)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are
|
5
|
+
# permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
8
|
+
# conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
11
|
+
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
|
13
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
14
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
15
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
16
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
17
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
18
|
+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
|
+
#
|
20
|
+
# The views and conclusions contained in the software and documentation are those of the
|
21
|
+
# authors and should not be interpreted as representing official policies, either expressed
|
22
|
+
# or implied, of Giovanni Capuano.
|
23
|
+
#++
|
24
|
+
|
25
|
+
module Zanox
|
26
|
+
class AdSpace < Item
|
27
|
+
attr_reader :pid, :name, :url, :description, :type, :visitors, :impressions,
|
28
|
+
:scope, :regions, :categories, :language, :check_number
|
29
|
+
|
30
|
+
###################
|
31
|
+
# - pid (Integer) AdSpace ID
|
32
|
+
# - name (String) The name of the adspace
|
33
|
+
# - url (String) The URL to the adspace
|
34
|
+
# - description (String) The description of the adspace
|
35
|
+
# - type (String) The type of the adspace (website, email, searchengine)
|
36
|
+
# - visitors (Integer) How many visitors Zanox tracked for you
|
37
|
+
# - impressions (Integer) The number of impressions of the adspace
|
38
|
+
# - scope (String) The scope of the adspace (private, bussiness)
|
39
|
+
# - regions (String[]) The regions where the adspace works
|
40
|
+
# - categories (String[]) The categories of the adspace
|
41
|
+
# - language (String) The language used inside the adspace
|
42
|
+
# - check_number (Integer)
|
43
|
+
###################
|
44
|
+
def initialize(data)
|
45
|
+
@pid = data['@id'].to_i
|
46
|
+
@name = data['name']
|
47
|
+
@url = data['url']
|
48
|
+
@description = data['description']
|
49
|
+
@type = data['adspaceType']
|
50
|
+
@visitors = data['visitors'].to_i
|
51
|
+
@impressions = data['impressions'].to_i
|
52
|
+
@scope = data['scope']
|
53
|
+
@regions = [data['regions'].try { |r| r.map(&:values) }].flatten.compact
|
54
|
+
@categories = [].tap do |categories|
|
55
|
+
categories_ = data['categories'].try { |p| p[0]['category'] }
|
56
|
+
data['categories'].try { |p| p[0]['category'] }.each do |category|
|
57
|
+
categories << {
|
58
|
+
id: category['@id'],
|
59
|
+
name: category['$'],
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
@language = data['language']
|
64
|
+
@check_number = data['checkNumber']
|
65
|
+
end
|
66
|
+
|
67
|
+
class << self
|
68
|
+
def find(args = {})
|
69
|
+
response = API.request(:adspaces, args)
|
70
|
+
response.adspace_items.map { |adspace| new(adspace) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are
|
5
|
+
# permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
8
|
+
# conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
11
|
+
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
|
13
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
14
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
15
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
16
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
17
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
18
|
+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
|
+
#
|
20
|
+
# The views and conclusions contained in the software and documentation are those of the
|
21
|
+
# authors and should not be interpreted as representing official policies, either expressed
|
22
|
+
# or implied, of Giovanni Capuano.
|
23
|
+
#++
|
24
|
+
|
25
|
+
module Zanox
|
26
|
+
class Item
|
27
|
+
include Hashable
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
raise NotImplementedError, '#initialize has not been implemented'
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def find(*args)
|
35
|
+
raise NotImplementedError, '#find has not been implemented'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are
|
5
|
+
# permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
8
|
+
# conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
11
|
+
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
|
13
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
14
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
15
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
16
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
17
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
18
|
+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
|
+
#
|
20
|
+
# The views and conclusions contained in the software and documentation are those of the
|
21
|
+
# authors and should not be interpreted as representing official policies, either expressed
|
22
|
+
# or implied, of Giovanni Capuano.
|
23
|
+
#++
|
24
|
+
|
25
|
+
module Zanox
|
26
|
+
class Product < Item
|
27
|
+
attr_reader :pid, :name, :program, :description, :excerpt, :manufacturer, :category,
|
28
|
+
:images, :currency, :price, :shipping_costs, :delivery_time, :tracking_link
|
29
|
+
|
30
|
+
###################
|
31
|
+
# - pid (String) Product ID
|
32
|
+
# - name (String) The name of the product
|
33
|
+
# - program (Hash) Hash containing the id and the name of the shop which sells this product (e.g. EuronicsIT)
|
34
|
+
# - description (HTML) The description of the product
|
35
|
+
# - excerpt (String) A short description of the product
|
36
|
+
# - manufacturer (String) The manufacturer of the product (e.g. Apple)
|
37
|
+
# - images (String[]) A collection of images representing the product in different sizes
|
38
|
+
# - currency (String) The currency used to calculate the price
|
39
|
+
# - price (Float) The price of the product calculated with the relative currency
|
40
|
+
# - shipping_costs (Float) The price of the shipping
|
41
|
+
# - delivery_time (Integer) The number of the days required by the shop to deliver the product
|
42
|
+
# - tracking_link (String ) The link that redirects to the advertiser's shop
|
43
|
+
###################
|
44
|
+
def initialize(data)
|
45
|
+
@pid = data['@id']
|
46
|
+
@name = data['name']
|
47
|
+
@program = {
|
48
|
+
id: data['program']['@id'].to_i,
|
49
|
+
name: data['program']['$']
|
50
|
+
}
|
51
|
+
@description = strip_cdata(data['descriptionLong'])
|
52
|
+
@excerpt = data['description']
|
53
|
+
@manufacturer = data['manufacturer']
|
54
|
+
@category = data['merchantCategory']
|
55
|
+
@images = {
|
56
|
+
small: data['image'].try { |i| i['small'] },
|
57
|
+
medium: data['image'].try { |i| i['medium'] },
|
58
|
+
large: data['image'].try { |i| i['large'] },
|
59
|
+
}
|
60
|
+
@currency = data['currency']
|
61
|
+
@price = data['price'].to_f
|
62
|
+
@shipping_costs = data['shippingCosts'].try(:to_f)
|
63
|
+
@delivery_time = only_numbers(data['deliveryTime'])
|
64
|
+
@tracking_link = data['trackingLinks'].try { |d| d['trackingLink'] }.try { |d| d[0] }.try { |d| d['ppc'] }
|
65
|
+
end
|
66
|
+
|
67
|
+
class << self
|
68
|
+
def find(keyword, args = {})
|
69
|
+
args.merge!({ q: keyword })
|
70
|
+
response = API.request(:products, args)
|
71
|
+
response.product_items.map { |product| new(product) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def from_shop(shop_id)
|
75
|
+
response = API.request(:products, programs: shop_id)
|
76
|
+
response.product_items.map { |product| new(product) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def strip_cdata(s)
|
82
|
+
s ? s.gsub(/<!\[CDATA\[(.*)\]\]>/, '\1') : s
|
83
|
+
end
|
84
|
+
|
85
|
+
def only_numbers(s)
|
86
|
+
s ? s.scan(/\d+/).last.to_i : s
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are
|
5
|
+
# permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
8
|
+
# conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
11
|
+
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
|
13
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
14
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
15
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
16
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
17
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
18
|
+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
|
+
#
|
20
|
+
# The views and conclusions contained in the software and documentation are those of the
|
21
|
+
# authors and should not be interpreted as representing official policies, either expressed
|
22
|
+
# or implied, of Giovanni Capuano.
|
23
|
+
#++
|
24
|
+
|
25
|
+
module Zanox
|
26
|
+
class ProgramApplication < Item
|
27
|
+
attr_reader :pid, :program, :adspace, :status, :allow_tpv
|
28
|
+
|
29
|
+
###################
|
30
|
+
# - pid (Integer) ProgramApplication ID
|
31
|
+
# - program (Hash) Infos about the program (activation status, id and name)
|
32
|
+
# - adspace (Hash) Infos about the adspace (id and name)
|
33
|
+
# - status (String) The status of the program (open, confirmed, rejected, deferred, waiting, blocked, terminated, canceled, called, declined, deleted)
|
34
|
+
# - allow_tpv (Boolean)
|
35
|
+
###################
|
36
|
+
def initialize(data)
|
37
|
+
@pid = data['@id'].to_i
|
38
|
+
@program = {
|
39
|
+
active: data['program']['@active'] == 'true',
|
40
|
+
id: data['program']['@id'].to_i,
|
41
|
+
name: data['program']['$']
|
42
|
+
}
|
43
|
+
@adspace = {
|
44
|
+
id: data['adspace']['@id'],
|
45
|
+
name: data['adspace']['$']
|
46
|
+
}
|
47
|
+
@status = data['status']
|
48
|
+
@allow_tpv = data['allowTpv']
|
49
|
+
end
|
50
|
+
|
51
|
+
class << self
|
52
|
+
def find(args = {})
|
53
|
+
response = API.request(:programapplications, args)
|
54
|
+
response.program_application_items.map { |program_application| new(program_application) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are
|
5
|
+
# permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
8
|
+
# conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
11
|
+
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
|
13
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
14
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
15
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
16
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
17
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
18
|
+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
|
+
#
|
20
|
+
# The views and conclusions contained in the software and documentation are those of the
|
21
|
+
# authors and should not be interpreted as representing official policies, either expressed
|
22
|
+
# or implied, of Giovanni Capuano.
|
23
|
+
#++
|
24
|
+
|
25
|
+
module Zanox
|
26
|
+
class Shop < Item
|
27
|
+
attr_reader :pid, :name, :rank, :description, :excerpt, :products_count,
|
28
|
+
:regions, :categories, :url, :image, :currency, :available, :terms, :policies
|
29
|
+
|
30
|
+
###################
|
31
|
+
# - pid (Integer) Shop ID
|
32
|
+
# - name (String) The name of the product
|
33
|
+
# - rank (Float) The rank of the shop
|
34
|
+
# - description (HTML) The description of the shop
|
35
|
+
# - excerpt (String) A short description of the shop
|
36
|
+
# - products_count (Integer) The number of products in stock
|
37
|
+
# - regions (String[]) A collection of regions where the shop is located
|
38
|
+
# - categories (String[]) A collection of the main categories of products
|
39
|
+
# - url (String) The direct link to the shop
|
40
|
+
# - image (String) An image representing the shop
|
41
|
+
# - currency (String) The currency used inside the shop
|
42
|
+
# - terms (HTML) The terms applied by the shop
|
43
|
+
# - policies (String[]) A collection of the policies followed by the shop
|
44
|
+
###################
|
45
|
+
def initialize(data)
|
46
|
+
@pid = data['@id'].to_i
|
47
|
+
@name = data['name']
|
48
|
+
@rank = data['adrank'].to_f
|
49
|
+
@description = strip_cdata(data['descriptionLocal'])
|
50
|
+
@excerpt = data['description']
|
51
|
+
@products_count = data['products'].to_i
|
52
|
+
@regions = [data['regions'].try { |r| r.map(&:values) }].flatten.compact
|
53
|
+
@categories = [].tap do |categories|
|
54
|
+
[data['categories'].try { |p| p[0]['category'] }].flatten.each do |category|
|
55
|
+
categories << {
|
56
|
+
id: category['@id'],
|
57
|
+
name: category['$'],
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
@url = data['url']
|
62
|
+
@image = data['image']
|
63
|
+
@currency = data['currency']
|
64
|
+
@terms = strip_cdata(data['terms'])
|
65
|
+
@policies = [].tap do |policies|
|
66
|
+
[data['policies'].try { |p| p['policy'] }].flatten.each do |policy|
|
67
|
+
policies << {
|
68
|
+
id: policy['@id'],
|
69
|
+
name: policy['$'],
|
70
|
+
} if policy
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class << self
|
76
|
+
def find(param, args = {})
|
77
|
+
param.is_a?(Numeric) ? find_by_id(param) : find_by_keyword(param)
|
78
|
+
end
|
79
|
+
|
80
|
+
def find_by_id(id, args = {})
|
81
|
+
response = ::Zanox::API.request("programs/program/#{id}", args)
|
82
|
+
response.program_item.map { |program| new(program) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def find_by_keyword(keyword, args = {})
|
86
|
+
args.merge!({ q: keyword })
|
87
|
+
response = API.request(:programs, args)
|
88
|
+
response.program_items.map { |program| new(program) }
|
89
|
+
end
|
90
|
+
|
91
|
+
# TODO: we could cache these results
|
92
|
+
def confirmed_shops
|
93
|
+
confirmed_ids.map { |id| find(id) }.flatten
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
def confirmed
|
98
|
+
adspaces = AdSpace.find.first
|
99
|
+
applications = ProgramApplication.find(adspace: adspaces.pid)
|
100
|
+
applications.select { |application| application.status == 'confirmed' }
|
101
|
+
end
|
102
|
+
|
103
|
+
def confirmed_ids
|
104
|
+
confirmed.map { |application| application.program[:id] }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def strip_cdata(s)
|
110
|
+
s ? s.gsub(/<!\[CDATA\[(.*)\]\]>/, '\1') : s
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/zanox/response.rb
CHANGED
data/lib/zanox/version.rb
CHANGED
data/lib/zanox.rb
CHANGED
@@ -22,6 +22,7 @@
|
|
22
22
|
# or implied, of Giovanni Capuano.
|
23
23
|
#++
|
24
24
|
require 'httparty'
|
25
|
+
require 'ruby-try'
|
25
26
|
require 'openssl'
|
26
27
|
|
27
28
|
require 'zanox/logger'
|
@@ -30,4 +31,12 @@ require 'zanox/exceptions/access_denied'
|
|
30
31
|
require 'zanox/exceptions/invalid_request'
|
31
32
|
require 'zanox/response'
|
32
33
|
require 'zanox/api'
|
34
|
+
|
35
|
+
require 'zanox/hashable'
|
36
|
+
require 'zanox/resources/item'
|
37
|
+
require 'zanox/resources/adspace'
|
38
|
+
require 'zanox/resources/product'
|
39
|
+
require 'zanox/resources/program_application'
|
40
|
+
require 'zanox/resources/shop'
|
41
|
+
|
33
42
|
require 'zanox/version'
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Zanox::Product do
|
4
|
+
before :each do
|
5
|
+
Zanox::API::Session.connect_id = '43EEF0445509C7205827'
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#find' do
|
9
|
+
let(:iphone) { Zanox::Product.find('iphone') }
|
10
|
+
let(:book) { Zanox::Product.find('book') }
|
11
|
+
let(:nike) { Zanox::Product.find('nike') }
|
12
|
+
|
13
|
+
it 'finds products by keyword' do
|
14
|
+
expect(iphone.length).to be >= 8
|
15
|
+
expect(book.length).to be >= 8
|
16
|
+
expect(nike.length).to be >= 8
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns a collection of Products' do
|
20
|
+
expect(iphone.last).to be_a(Zanox::Product)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#from_shop' do
|
25
|
+
let(:products) { Zanox::Product.from_shop(7187) }
|
26
|
+
|
27
|
+
it 'finds products by keyword' do
|
28
|
+
expect(products.length).to be >= 8
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns a collection of Products' do
|
32
|
+
expect(products.last).to be_a(Zanox::Product)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns only Products that belongs to given shop' do
|
36
|
+
expect(products.all? { |product| product.program[:id] == 7187 }).to be_truthy
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#initialize' do
|
41
|
+
let(:data) do
|
42
|
+
{
|
43
|
+
"@id" => "7f3b1f59484c49b8cbf6b70356b20d6f",
|
44
|
+
"name" => "Nike - Jordan - Socken - Weiß",
|
45
|
+
"modified" => "2015-04-28T03:06:58+02:00",
|
46
|
+
"program" => {"@id" => "7408", "$" => "Asos.com DE"},
|
47
|
+
"price" => 17.99,
|
48
|
+
"currency" => "EUR",
|
49
|
+
"trackingLinks" => { "trackingLink" =>
|
50
|
+
[
|
51
|
+
{
|
52
|
+
"@adspaceId" => "1009338",
|
53
|
+
"ppv" => "http://ad.zanox.com/ppv/?22436292C14041752&ULP=[[Nike/Nike-Jordan-Socks/Prod/pgeproduct.aspx?iid=4955490&istCompanyId=030f1ff6-3a15-4425-bccd-ba2bdee3fa38&istItemId=piiiarxql&istBid=t&channelref=affiliate]]&zpar9=[[43EEF0445509C7205827]]",
|
54
|
+
"ppc" => "http://ad.zanox.com/ppc/?22436292C14041752&ULP=[[Nike/Nike-Jordan-Socks/Prod/pgeproduct.aspx?iid=4955490&istCompanyId=030f1ff6-3a15-4425-bccd-ba2bdee3fa38&istItemId=piiiarxql&istBid=t&channelref=affiliate]]&zpar9=[[43EEF0445509C7205827]]"
|
55
|
+
}
|
56
|
+
]
|
57
|
+
},
|
58
|
+
"description" => "Nike - Jordan - Socken - Weiß - Farbe:Weiß",
|
59
|
+
"descriptionLong" => "ÜBER MICH Hauptmaterial: 58% Baumwolle, 39% Nylon, 3% Elastan SO PFLEGEN SIE MICH Wie auf dem Pflegeetikett angegeben in der Maschine waschen",
|
60
|
+
"manufacturer" => "Nike",
|
61
|
+
"deliveryTime" => "2 to 4 days",
|
62
|
+
"category" => {"@id" => "3230000", "$" => "Bodywear & Lingerie"},
|
63
|
+
"image" => {"large" => "http://images.asos-media.com/inv/media/0/9/4/5/4955490/white/image1xxl.jpg"},
|
64
|
+
"shippingCosts" => 3,
|
65
|
+
"shipping" => 3,
|
66
|
+
"merchantCategory" => "Startseite / Herren / Nike / Unterwäsche & Socken",
|
67
|
+
"merchantProductId" => 3420722
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:invalid_data) do
|
72
|
+
obj = data.dup
|
73
|
+
obj['image'] = nil
|
74
|
+
obj['price'] = nil
|
75
|
+
obj
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'valid input' do
|
79
|
+
it 'creates a new instance of Product' do
|
80
|
+
product = Zanox::Product.new(data)
|
81
|
+
expect(product.price).to be_a(Float)
|
82
|
+
expect(product.shipping_costs).to be_a(Float)
|
83
|
+
expect(product.delivery_time).to eq 4
|
84
|
+
expect(product.description).to eq 'ÜBER MICH Hauptmaterial: 58% Baumwolle, 39% Nylon, 3% Elastan SO PFLEGEN SIE MICH Wie auf dem Pflegeetikett angegeben in der Maschine waschen'
|
85
|
+
expect(product.tracking_link).to eq 'http://ad.zanox.com/ppc/?22436292C14041752&ULP=[[Nike/Nike-Jordan-Socks/Prod/pgeproduct.aspx?iid=4955490&istCompanyId=030f1ff6-3a15-4425-bccd-ba2bdee3fa38&istItemId=piiiarxql&istBid=t&channelref=affiliate]]&zpar9=[[43EEF0445509C7205827]]'
|
86
|
+
expect(product.images).to be_a(Hash)
|
87
|
+
expect(product.images[:small]).to be_nil
|
88
|
+
expect(product.images[:large]).to eq 'http://images.asos-media.com/inv/media/0/9/4/5/4955490/white/image1xxl.jpg'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'invalid input' do
|
93
|
+
it 'creates a new instance of Product' do
|
94
|
+
product = Zanox::Product.new(invalid_data)
|
95
|
+
expect(product.price).to eq 0.0
|
96
|
+
expect(product.images.values.compact).to eq []
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Zanox::Shop do
|
4
|
+
describe '#find' do
|
5
|
+
let(:shops) { Zanox::Shop.find('zalando') }
|
6
|
+
|
7
|
+
it 'finds shops by keyword' do
|
8
|
+
expect(shops.length).to be > 0
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns a collection of Shops' do
|
12
|
+
expect(shops.last).to be_a(Zanox::Shop)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#confirmed' do
|
17
|
+
let(:programs) { Zanox::Shop.instance_eval { confirmed } }
|
18
|
+
|
19
|
+
it 'contains at least one program' do
|
20
|
+
expect(programs.length).to be > 0
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'contains only approved program' do
|
24
|
+
expect(programs.all? { |program| program.status == 'confirmed' }).to be_truthy
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
## Well, this test will never work with the default API keys...
|
29
|
+
# describe '#confirmed_shops' do
|
30
|
+
# let(:shops) { Zanox::Shop.confirmed_shops }
|
31
|
+
|
32
|
+
# it 'contains at least one shop' do
|
33
|
+
# expect(shops.length).to be > 0
|
34
|
+
# end
|
35
|
+
|
36
|
+
# it 'returns a collection of Shops' do
|
37
|
+
# expect(shops.last).to be_a(Zanox::Shop)
|
38
|
+
# end
|
39
|
+
|
40
|
+
# it 'returns only confirmed programs' do
|
41
|
+
# expect(shops.length).to be > 0
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
|
45
|
+
describe '#initialize' do
|
46
|
+
let(:data) do
|
47
|
+
{
|
48
|
+
"@id" => "2283",
|
49
|
+
"name" => "Amazon Buy VIP DE",
|
50
|
+
"adrank" => 4.1,
|
51
|
+
"applicationRequired" => true,
|
52
|
+
"description" => "Amazon BuyVIP – der Shopping Club für Fashion & Lifestyle. Verdienen Sie 6% Provision an unseren exklusiven Verkaufsaktionen mit Preisvorteilen von bis zu 70% auf begehrte Top Marken und Insider Labels sowie 1€ Provision für jedes neue Mitglied!",
|
53
|
+
"descriptionLocal" => "<![CDATA[<p> <strong>Sale-Vergütung jetzt auch für Bestandskunden! </strong></p><p> </p><p> <strong>Amazon BuyVIP</strong></p><p> Amazon BuyVIP – der Shopping Club für Fashion & Lifestyle. Der Zutritt zu Amazon BuyVIP ist limitiert: Nur registrierte Mitglieder erhalten Zugang zu exklusiven und zeitlich begrenzten Verkaufsaktionen mit Preisvorteilen von bis zu 70% gegenüber der UVP des Herstellers. Angeboten werden begehrte Top Marken und Insider Labels aus dem Bereich Fashion und Lifestyle.</p><p> </p><p> <strong>Amazon BuyVIP Produktsortiment</strong></p><p> Das Sortiment umfasst Verkaufsaktionen mit folgenden Produkten:</p><p> · Damen-, Herren- und Kindermode</p><p> · Accessories wie Taschen, Schals, Schmuck und Sonnenbrillen</p><p> · Wellness- & Beauty-Produkte</p><p> · Edle Wohnaccessoires und Möbel</p><p> </p><p> <strong>Amazon BuyVIP Publisher-Vorteile auf einen Blick</strong></p><p> · Sale-Vergütung für Neu- & Bestandskunden</p><p> · Conversionstarke Werbemittel, saisonal gepflegt</p><p> · Cookie-Laufzeit: 30 Tage</p><p> · Regelmäßiger Affiliate-Newsletter</p><p> · Saisonale Pflege aller Werbemittel</p><p> </p><p> <strong>Amazon BuyVIP Kundenvorteile auf einen Blick</strong></p><p> · Breites Angebot begehrter Top Marken und Insider Labels</p><p> · Bis zu 70% Preisvorteil gegenüber der UVP des Herstellers</p><p> · Einfache Anmeldung mit dem Amazon Konto</p><p> · Kostenlose & unverbindliche Mitgliedschaft</p><p> · Ein Warenkorb für alle Verkaufsaktionen</p><p> · Gratisversand ab 100 Euro Bestellwert</p><p> · Bezahlung erst beim Versand der Bestellung</p><p> · Versand in 27 Länder</p><p> · Servicezeiten von 6 bis 24 Uhr</p><p> · 30 Tage Rückgabegarantie</p><p> · 10 Euro Gutschein für jeden eingeladenen Freund</p><p> </p><p> <strong>Amazon BuyVIP Provisionsmodell</strong></p><p> </p><p> Sale: 6% auf jeden bestätigten Sale (Neu- & Bestandskunden)</p><p> Lead: 1 EUR für jedes valide neue Mitglied<br /> </p><p> Ab 1.500 Leads pro Monat erhalten Sie 1,50 EUR pro Lead und 6% pro Sale.</p><p> </p><p> <strong>Die Sale-Provisionen gelten auch für Bestandskunden!</strong><br /> <br /> </p><p> </p><p> <strong>Suchmaschinenmarketing</strong></p><p> SEM darf nur nach ausdrücklicher Einwilligung von Amazon BuyVIP angewendet werden.</p><p> · Die Verwendung der Standard Amazon BuyVIP Display-URL ist ausdrücklich untersagt. Sie benötigen eine eigene Domain.</p><p> · Wir weisen darauf hin, dass keine geschützten Brand Namen verwendet werden dürfen</p><p> · Die Buchung von Brand Keywords der direkten Mitbewerber zu Amazon BuyVIP ist ausdrücklich untersagt</p><p> · Die Buchung von BuyVIP Brand Keywords (auch Falschschreibweisen) ist ausdrücklich untersagt</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> </p><p> <strong>Was muss ich noch beachten, wenn ich Amazon BuyVIP bewerbe? </strong></p><p> · Jegliche Veränderungen der Verlinkungen sind nicht gestattet. Dies betrifft vor allem das Anhängen der Zanox-ID, Download und Einfügen von Werbemitteln auf Drittseiten, usw.</p><p> · Das Kommunizieren von Endpreisen aus dem Amazon BuyVIP Shop ist ausdrücklich untersagt.</p><p> · Es ist nicht gestattet, die Freundschaftswerbung von Amazon BuyVIP zu bewerben.</p><p> · Weiterhin nicht gestattet sind: Paidmails, Keyword Advertising, Forced Clicks, Meta-Netzwerke, Cashback </p><p> · Es ist nicht gestattet, gleichzeitig dieselbe Platzierung über das Amazon PartnerNet zu verlinken.</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> </p><p> <strong>Kontakt</strong></p><p> Für Fragen und Wünsche stehen wir Ihnen gerne zur Verfügung. Wenden Sie sich einfach an Ihren persönlichen Ansprechpartner:</p><p> </p><p> <strong>Adreana Starke</strong></p><p> E-Mail: adreana@amazon.com<br /> </p>]]>",
|
54
|
+
"products" => 0,
|
55
|
+
"vertical" => {
|
56
|
+
"@id" => "78",
|
57
|
+
"$" => "Retail&Shopping"
|
58
|
+
},
|
59
|
+
"regions" => [
|
60
|
+
{
|
61
|
+
"region" => "DE"
|
62
|
+
}
|
63
|
+
],
|
64
|
+
"categories" => [
|
65
|
+
{
|
66
|
+
"category" => [
|
67
|
+
{
|
68
|
+
"@id" => "11",
|
69
|
+
"$" => "Internet services"
|
70
|
+
},
|
71
|
+
{
|
72
|
+
"@id" => "33",
|
73
|
+
"$" => "Clothing & Accessories"
|
74
|
+
},
|
75
|
+
{
|
76
|
+
"@id" => "34",
|
77
|
+
"$" => "Shopping & Mail Order Shops"
|
78
|
+
}
|
79
|
+
]
|
80
|
+
}
|
81
|
+
],
|
82
|
+
"startDate" => "2006-08-01T02:00:00+02:00",
|
83
|
+
"url" => "http://de.buyvip.com",
|
84
|
+
"image" => "http://ui.zanox.com/images/programs/2283/2283_lgo_buy_vip.jpg",
|
85
|
+
"currency" => "EUR",
|
86
|
+
"status" => "active",
|
87
|
+
"terms" => "<p> <strong>Was muss ich noch beachten, wenn ich Amazon BuyVIP bewerbe? </strong></p><p> </p><p> · Jegliche Veränderungen der Verlinkungen sind nicht gestattet. Dies betrifft vor allem das Anhängen der Zanox-ID, Download und Einfügen von Werbemitteln auf Drittseiten, usw.</p><p> · Das Kommunizieren von Endpreisen aus dem Amazon BuyVIP Shop ist ausdrücklich untersagt.</p><p> · Weiterhin nicht gestattet sind: Paidmails, Keyword Advertising, Forced Clicks, Meta-Netzwerke, Cashback </p><p> · Es ist nicht gestattet, gleichzeitig dieselbe Platzierung über das Amazon PartnerNet zu verlinken.</p><p> · Es ist nicht gestattet, die Freundschaftswerbung von Amazon BuyVIP zu bewerben.</p><p> . SEM: eingeschränkt, siehe Regelungen in Branding</p><p> </p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p>",
|
88
|
+
"policies" => {
|
89
|
+
"policy" => [
|
90
|
+
{
|
91
|
+
"@id" => "102",
|
92
|
+
"$" => "Popups/Popunders allowed"
|
93
|
+
},
|
94
|
+
{
|
95
|
+
"@id" => "106",
|
96
|
+
"$" => "Cashback/Loyalty allowed"
|
97
|
+
},
|
98
|
+
{
|
99
|
+
"@id" => "105",
|
100
|
+
"$" => "Co-Registration allowed"
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"@id" => "103",
|
104
|
+
"$" => "Layers allowed"
|
105
|
+
},
|
106
|
+
{
|
107
|
+
"@id" => "107",
|
108
|
+
"$" => "Exclusive zanox advertiser"
|
109
|
+
}
|
110
|
+
]
|
111
|
+
},
|
112
|
+
"returnTimeLeads" => 2592000,
|
113
|
+
"returnTimeSales" => 2592000
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
let(:invalid_data) do
|
118
|
+
obj = data.dup
|
119
|
+
obj['regions'] = nil
|
120
|
+
obj['policies'] = nil
|
121
|
+
obj
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'valid input' do
|
125
|
+
it 'creates a new instance of Shop' do
|
126
|
+
shop = Zanox::Shop.new(data)
|
127
|
+
expect(shop.rank).to eq 4.1
|
128
|
+
expect(shop.products_count).to eq 0
|
129
|
+
expect(shop.regions).to eq ['DE']
|
130
|
+
expect(shop.description).to eq '<p> <strong>Sale-Vergütung jetzt auch für Bestandskunden! </strong></p><p> </p><p> <strong>Amazon BuyVIP</strong></p><p> Amazon BuyVIP – der Shopping Club für Fashion & Lifestyle. Der Zutritt zu Amazon BuyVIP ist limitiert: Nur registrierte Mitglieder erhalten Zugang zu exklusiven und zeitlich begrenzten Verkaufsaktionen mit Preisvorteilen von bis zu 70% gegenüber der UVP des Herstellers. Angeboten werden begehrte Top Marken und Insider Labels aus dem Bereich Fashion und Lifestyle.</p><p> </p><p> <strong>Amazon BuyVIP Produktsortiment</strong></p><p> Das Sortiment umfasst Verkaufsaktionen mit folgenden Produkten:</p><p> · Damen-, Herren- und Kindermode</p><p> · Accessories wie Taschen, Schals, Schmuck und Sonnenbrillen</p><p> · Wellness- & Beauty-Produkte</p><p> · Edle Wohnaccessoires und Möbel</p><p> </p><p> <strong>Amazon BuyVIP Publisher-Vorteile auf einen Blick</strong></p><p> · Sale-Vergütung für Neu- & Bestandskunden</p><p> · Conversionstarke Werbemittel, saisonal gepflegt</p><p> · Cookie-Laufzeit: 30 Tage</p><p> · Regelmäßiger Affiliate-Newsletter</p><p> · Saisonale Pflege aller Werbemittel</p><p> </p><p> <strong>Amazon BuyVIP Kundenvorteile auf einen Blick</strong></p><p> · Breites Angebot begehrter Top Marken und Insider Labels</p><p> · Bis zu 70% Preisvorteil gegenüber der UVP des Herstellers</p><p> · Einfache Anmeldung mit dem Amazon Konto</p><p> · Kostenlose & unverbindliche Mitgliedschaft</p><p> · Ein Warenkorb für alle Verkaufsaktionen</p><p> · Gratisversand ab 100 Euro Bestellwert</p><p> · Bezahlung erst beim Versand der Bestellung</p><p> · Versand in 27 Länder</p><p> · Servicezeiten von 6 bis 24 Uhr</p><p> · 30 Tage Rückgabegarantie</p><p> · 10 Euro Gutschein für jeden eingeladenen Freund</p><p> </p><p> <strong>Amazon BuyVIP Provisionsmodell</strong></p><p> </p><p> Sale: 6% auf jeden bestätigten Sale (Neu- & Bestandskunden)</p><p> Lead: 1 EUR für jedes valide neue Mitglied<br /> </p><p> Ab 1.500 Leads pro Monat erhalten Sie 1,50 EUR pro Lead und 6% pro Sale.</p><p> </p><p> <strong>Die Sale-Provisionen gelten auch für Bestandskunden!</strong><br /> <br /> </p><p> </p><p> <strong>Suchmaschinenmarketing</strong></p><p> SEM darf nur nach ausdrücklicher Einwilligung von Amazon BuyVIP angewendet werden.</p><p> · Die Verwendung der Standard Amazon BuyVIP Display-URL ist ausdrücklich untersagt. Sie benötigen eine eigene Domain.</p><p> · Wir weisen darauf hin, dass keine geschützten Brand Namen verwendet werden dürfen</p><p> · Die Buchung von Brand Keywords der direkten Mitbewerber zu Amazon BuyVIP ist ausdrücklich untersagt</p><p> · Die Buchung von BuyVIP Brand Keywords (auch Falschschreibweisen) ist ausdrücklich untersagt</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> </p><p> <strong>Was muss ich noch beachten, wenn ich Amazon BuyVIP bewerbe? </strong></p><p> · Jegliche Veränderungen der Verlinkungen sind nicht gestattet. Dies betrifft vor allem das Anhängen der Zanox-ID, Download und Einfügen von Werbemitteln auf Drittseiten, usw.</p><p> · Das Kommunizieren von Endpreisen aus dem Amazon BuyVIP Shop ist ausdrücklich untersagt.</p><p> · Es ist nicht gestattet, die Freundschaftswerbung von Amazon BuyVIP zu bewerben.</p><p> · Weiterhin nicht gestattet sind: Paidmails, Keyword Advertising, Forced Clicks, Meta-Netzwerke, Cashback </p><p> · Es ist nicht gestattet, gleichzeitig dieselbe Platzierung über das Amazon PartnerNet zu verlinken.</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> </p><p> <strong>Kontakt</strong></p><p> Für Fragen und Wünsche stehen wir Ihnen gerne zur Verfügung. Wenden Sie sich einfach an Ihren persönlichen Ansprechpartner:</p><p> </p><p> <strong>Adreana Starke</strong></p><p> E-Mail: adreana@amazon.com<br /> </p>'
|
131
|
+
expect(shop.excerpt).to eq 'Amazon BuyVIP – der Shopping Club für Fashion & Lifestyle. Verdienen Sie 6% Provision an unseren exklusiven Verkaufsaktionen mit Preisvorteilen von bis zu 70% auf begehrte Top Marken und Insider Labels sowie 1€ Provision für jedes neue Mitglied!'
|
132
|
+
expect(shop.terms).to be_a(String)
|
133
|
+
expect(shop.policies).to be_a(Array)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'invalid input' do
|
138
|
+
it 'creates a new instance of Shop' do
|
139
|
+
shop = Zanox::Shop.new(invalid_data)
|
140
|
+
expect(shop.regions).to eq []
|
141
|
+
expect(shop.policies).to eq []
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/zanoxrb.gemspec
CHANGED
@@ -15,6 +15,7 @@ Gem::Specification.new { |s|
|
|
15
15
|
s.require_paths = ['lib']
|
16
16
|
|
17
17
|
s.add_dependency 'httparty', '~> 0.13'
|
18
|
+
s.add_dependency 'ruby-try', '~> 1.1'
|
18
19
|
s.add_development_dependency 'rake', '~> 10.4'
|
19
20
|
s.add_development_dependency 'rspec', '~> 3.3'
|
20
21
|
s.add_development_dependency 'rspec-collection_matchers', '~> 1.1'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zanoxrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.5'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Giovanni Capuano
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '0.13'
|
26
26
|
type: :runtime
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.1'
|
33
|
+
name: ruby-try
|
34
|
+
prerelease: false
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.1'
|
40
|
+
type: :runtime
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
version_requirements: !ruby/object:Gem::Requirement
|
29
43
|
requirements:
|
@@ -83,7 +97,13 @@ files:
|
|
83
97
|
- lib/zanox/api.rb
|
84
98
|
- lib/zanox/exceptions/access_denied.rb
|
85
99
|
- lib/zanox/exceptions/invalid_request.rb
|
100
|
+
- lib/zanox/hashable.rb
|
86
101
|
- lib/zanox/logger.rb
|
102
|
+
- lib/zanox/resources/adspace.rb
|
103
|
+
- lib/zanox/resources/item.rb
|
104
|
+
- lib/zanox/resources/product.rb
|
105
|
+
- lib/zanox/resources/program_application.rb
|
106
|
+
- lib/zanox/resources/shop.rb
|
87
107
|
- lib/zanox/response.rb
|
88
108
|
- lib/zanox/session.rb
|
89
109
|
- lib/zanox/version.rb
|
@@ -91,6 +111,8 @@ files:
|
|
91
111
|
- specs/profiles_spec.rb
|
92
112
|
- specs/program_application_spec.rb
|
93
113
|
- specs/programs_spec.rb
|
114
|
+
- specs/resources/product_spec.rb
|
115
|
+
- specs/resources/shop_spec.rb
|
94
116
|
- specs/response_spec.rb
|
95
117
|
- specs/spec_helper.rb
|
96
118
|
- zanoxrb.gemspec
|