7digital 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +8 -1
- data/lib/sevendigital.rb +4 -2
- data/lib/sevendigital/api_operator.rb +92 -94
- data/lib/sevendigital/api_operator_cached.rb +55 -33
- data/lib/sevendigital/api_request.rb +50 -54
- data/lib/sevendigital/client.rb +15 -6
- data/lib/sevendigital/client_configuration.rb +0 -3
- data/lib/sevendigital/client_digestors.rb +15 -0
- data/lib/sevendigital/client_managers.rb +11 -1
- data/lib/sevendigital/digestion_tract/api_response_digestor.rb +31 -40
- data/lib/sevendigital/digestion_tract/artist_digestor.rb +16 -13
- data/lib/sevendigital/digestion_tract/basket_digestor.rb +5 -5
- data/lib/sevendigital/digestion_tract/basket_item_digestor.rb +12 -12
- data/lib/sevendigital/digestion_tract/chart_item_digestor.rb +17 -11
- data/lib/sevendigital/digestion_tract/country_digestor.rb +16 -0
- data/lib/sevendigital/digestion_tract/digestor.rb +82 -28
- data/lib/sevendigital/digestion_tract/download_url_digestor.rb +10 -7
- data/lib/sevendigital/digestion_tract/format_digestor.rb +11 -9
- data/lib/sevendigital/digestion_tract/label_digestor.rb +8 -7
- data/lib/sevendigital/digestion_tract/list_digestor.rb +24 -0
- data/lib/sevendigital/digestion_tract/list_item_digestor.rb +26 -0
- data/lib/sevendigital/digestion_tract/locker_digestor.rb +9 -5
- data/lib/sevendigital/digestion_tract/locker_release_digestor.rb +13 -7
- data/lib/sevendigital/digestion_tract/locker_track_digestor.rb +13 -9
- data/lib/sevendigital/digestion_tract/oauth_access_token_digestor.rb +7 -3
- data/lib/sevendigital/digestion_tract/oauth_request_token_digestor.rb +7 -3
- data/lib/sevendigital/digestion_tract/pager_digestor.rb +13 -9
- data/lib/sevendigital/digestion_tract/price_digestor.rb +15 -12
- data/lib/sevendigital/digestion_tract/release_digestor.rb +26 -34
- data/lib/sevendigital/digestion_tract/tag_digestor.rb +8 -7
- data/lib/sevendigital/digestion_tract/track_digestor.rb +27 -28
- data/lib/sevendigital/digestion_tract/user_card_digestor.rb +9 -8
- data/lib/sevendigital/digestion_tract/user_digestor.rb +8 -7
- data/lib/sevendigital/management/artist_manager.rb +9 -11
- data/lib/sevendigital/management/basket_manager.rb +4 -4
- data/lib/sevendigital/management/country_manager.rb +11 -0
- data/lib/sevendigital/management/list_manager.rb +18 -0
- data/lib/sevendigital/management/oauth_manager.rb +2 -2
- data/lib/sevendigital/management/release_manager.rb +9 -11
- data/lib/sevendigital/management/tag_manager.rb +1 -1
- data/lib/sevendigital/management/track_manager.rb +4 -5
- data/lib/sevendigital/management/user_card_manager.rb +2 -2
- data/lib/sevendigital/management/user_manager.rb +9 -4
- data/lib/sevendigital/model/api_response.rb +12 -4
- data/lib/sevendigital/model/artist.rb +5 -0
- data/lib/sevendigital/model/list.rb +5 -0
- data/lib/sevendigital/model/list_item.rb +9 -0
- data/lib/sevendigital/model/release.rb +2 -2
- data/lib/sevendigital/model/sevendigital_object.rb +1 -1
- data/lib/sevendigital/model/user.rb +12 -1
- data/lib/sevendigital/pager.rb +2 -6
- data/lib/sevendigital/version.rb +1 -1
- data/spec/api_operator_cached_spec.rb +14 -14
- data/spec/api_operator_spec.rb +18 -34
- data/spec/digestion_tract/api_response_digestor_spec.rb +26 -25
- data/spec/digestion_tract/artist_digestor_spec.rb +9 -9
- data/spec/digestion_tract/basket_digestor_spec.rb +2 -2
- data/spec/digestion_tract/basket_item_digestor_spec.rb +4 -4
- data/spec/digestion_tract/chart_digestor_spec.rb +4 -4
- data/spec/digestion_tract/country_digestor_spec.rb +33 -0
- data/spec/digestion_tract/digestor_spec.rb +34 -0
- data/spec/digestion_tract/download_url_digestor_spec.rb +2 -2
- data/spec/digestion_tract/format_digestor_spec.rb +2 -2
- data/spec/digestion_tract/label_digestor_spec.rb +2 -2
- data/spec/digestion_tract/list_digestor_spec.rb +32 -0
- data/spec/digestion_tract/list_item_digestor_spec.rb +80 -0
- data/spec/digestion_tract/locker_digestor_spec.rb +2 -2
- data/spec/digestion_tract/locker_release_digestor_spec.rb +5 -5
- data/spec/digestion_tract/locker_track_digestor_spec.rb +4 -4
- data/spec/digestion_tract/oauth_access_token_digestor_spec.rb +2 -2
- data/spec/digestion_tract/oauth_request_token_digestor_spec.rb +2 -2
- data/spec/digestion_tract/pager_digestor_spec.rb +3 -3
- data/spec/digestion_tract/price_digestor_spec.rb +4 -4
- data/spec/digestion_tract/release_digestor_spec.rb +19 -5
- data/spec/digestion_tract/tag_digestor_spec.rb +3 -3
- data/spec/digestion_tract/track_digestor_spec.rb +4 -4
- data/spec/digestion_tract/user_card_digestor_spec.rb +5 -5
- data/spec/digestion_tract/user_digestor_spec.rb +4 -6
- data/spec/integration/artist_spec.rb +86 -0
- data/spec/integration/country_spec.rb +18 -0
- data/spec/integration/list_spec.rb +22 -0
- data/spec/integration/purchasing_spec.rb +24 -0
- data/spec/integration/release_spec.rb +34 -0
- data/spec/integration/sevendigital_spec.yml +5 -0
- data/spec/integration/track_spec.rb +23 -0
- data/spec/integration/user_spec.rb +22 -0
- data/spec/management/artist_manager_spec.rb +32 -11
- data/spec/management/basket_manager_spec.rb +4 -4
- data/spec/management/country_manager_spec.rb +34 -0
- data/spec/management/list_manager_spec.rb +27 -0
- data/spec/management/oauth_manager_spec.rb +4 -4
- data/spec/management/release_manager_spec.rb +13 -13
- data/spec/management/tag_manager_spec.rb +1 -1
- data/spec/management/track_manager_spec.rb +4 -4
- data/spec/management/user_card_manager_spec.rb +2 -2
- data/spec/management/user_manager_spec.rb +20 -4
- data/spec/model/api_response_spec.rb +3 -3
- data/spec/model/artist_spec.rb +2 -2
- data/spec/model/sevendigital_object_spec.rb +4 -4
- data/spec/model/user_spec.rb +21 -0
- data/spec/spec_helper.rb +31 -11
- data/spec/test-xml/methods/country/resolve.xml +7 -0
- data/spec/test-xml/methods/editorial/list.xml +171 -0
- data/spec/test-xml/methods/user/details.xml +5 -0
- data/spec/test-xml/objects/artist.xml +1 -0
- data/spec/test-xml/objects/list.xml +89 -0
- data/spec/test-xml/objects/list_item_list.xml +86 -0
- data/spec/test-xml/objects/list_item_release.xml +14 -0
- data/spec/test-xml/objects/nested_release_list.xml +23 -0
- metadata +126 -273
- data/lib/sevendigital/peachy_patchy.rb +0 -9
- data/lib/sevendigital/proxy_police.rb +0 -28
- data/spec/coverage/assets/0.3.9/app.js +0 -66
- data/spec/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
- data/spec/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/spec/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/spec/coverage/assets/0.3.9/favicon.png +0 -0
- data/spec/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
- data/spec/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
- data/spec/coverage/assets/0.3.9/jquery.timeago.js +0 -141
- data/spec/coverage/assets/0.3.9/jquery.url.js +0 -174
- data/spec/coverage/assets/0.3.9/loading.gif +0 -0
- data/spec/coverage/assets/0.3.9/magnify.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/spec/coverage/assets/0.3.9/stylesheet.css +0 -341
- data/spec/coverage/index.html +0 -47481
- data/spec/coverage/resultset.yml +0 -3556
- data/spec/model/coverage/assets/0.3.9/app.js +0 -66
- data/spec/model/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
- data/spec/model/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/spec/model/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/spec/model/coverage/assets/0.3.9/favicon.png +0 -0
- data/spec/model/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
- data/spec/model/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
- data/spec/model/coverage/assets/0.3.9/jquery.timeago.js +0 -141
- data/spec/model/coverage/assets/0.3.9/jquery.url.js +0 -174
- data/spec/model/coverage/assets/0.3.9/loading.gif +0 -0
- data/spec/model/coverage/assets/0.3.9/magnify.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/model/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/spec/model/coverage/assets/0.3.9/stylesheet.css +0 -341
- data/spec/model/coverage/index.html +0 -8637
- data/spec/model/coverage/resultset.yml +0 -642
- data/spec/pager_spec.rb +0 -7
- data/spec/peachy_spec_helper_patch.rb +0 -7
- data/spec/proxy_police_spec.rb +0 -70
- data/spec/sevendigital_spec.rb +0 -51
- data/spec/sevendigital_spec.yml +0 -5
data/README.rdoc
CHANGED
@@ -4,22 +4,29 @@ This is a ruby wrapper for the 7digital API.
|
|
4
4
|
|
5
5
|
==About 7digital
|
6
6
|
|
7
|
-
7digital.com is an online music store operating in over
|
7
|
+
7digital.com is an online music store operating in over 30 countries and offering more than 20 million high quality DRM free MP3s (320kbps) from all major labels and wide range of idependent labels and distributors. 7digital API will give you access to the full catalogue including high quality album art, 30s preview clips for all tracks, commissions on sales, integrated purchasing and full length streaming. More details at http://developer.7digital.net
|
8
8
|
|
9
9
|
==Installation
|
10
10
|
|
11
11
|
gem install 7digital
|
12
12
|
|
13
|
+
|
13
14
|
==Quick start example
|
14
15
|
|
15
16
|
|
16
17
|
require "sevendigital"
|
18
|
+
|
17
19
|
api_client = Sevendigital::Client.new(:oauth_consumer_key => "YOUR_KEY_HERE", :country => "GB")
|
20
|
+
|
18
21
|
an_artist = api_client.artist.search("radiohead").first
|
22
|
+
|
19
23
|
a_release = an_artist.releases(:page_size=>100).sort_by{|release| release.year}.last
|
24
|
+
|
20
25
|
puts "the latest #{an_artist.name} release is #{a_release.title} from #{a_release.year}"
|
26
|
+
|
21
27
|
puts "go and buy it at #{a_release.url} !"
|
22
28
|
|
29
|
+
|
23
30
|
==Usage details
|
24
31
|
|
25
32
|
===Initializing & configuring an API Client
|
data/lib/sevendigital.rb
CHANGED
@@ -43,8 +43,10 @@ module Sevendigital
|
|
43
43
|
|
44
44
|
end # module 7digital
|
45
45
|
|
46
|
-
require '
|
47
|
-
|
46
|
+
require 'nokogiri'
|
47
|
+
require 'bigdecimal'
|
48
|
+
require 'bigdecimal/util'
|
49
|
+
require 'logger'
|
48
50
|
require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'client_configuration')
|
49
51
|
require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'management', 'manager')
|
50
52
|
require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'digestion_tract', 'digestor')
|
@@ -11,121 +11,119 @@ module Sevendigital
|
|
11
11
|
#deals with OAuth signing requests that require signature, making sure parameters are in correct format etc
|
12
12
|
class ApiOperator # :nodoc:
|
13
13
|
|
14
|
-
|
14
|
+
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def initialize(client)
|
17
|
+
@client = client
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
def call_api(api_request)
|
21
|
+
make_http_request_and_digest(api_request).tap do |api_response|
|
22
|
+
@client.log(:verbose) { "ApiOperator: API Response: #{api_response}" }
|
23
|
+
end
|
24
|
+
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
def get_request_uri(api_request)
|
27
|
+
api_request.signature_scheme = :query_string if api_request.requires_signature?
|
28
|
+
http_client, http_request = create_http_request(api_request)
|
29
|
+
path = http_request.instance_variable_get("@path")
|
30
|
+
host = http_client.instance_variable_get("@address")
|
31
|
+
port = http_client.instance_variable_get("@port")
|
32
|
+
scheme = port == 443 ? "https" : "http"
|
33
|
+
"#{scheme}://#{host}#{path}"
|
34
|
+
end
|
35
35
|
|
36
|
-
|
36
|
+
def make_http_request_and_digest(api_request)
|
37
37
|
digest_http_response(make_http_request(api_request))
|
38
|
-
|
39
|
-
|
40
|
-
def make_http_request(api_request)
|
41
|
-
|
42
|
-
http_client, http_request = create_http_request(api_request)
|
43
|
-
|
44
|
-
http_client.set_debug_output($stdout) if @client.very_verbose?
|
45
|
-
log_request(http_request) if @client.verbose?
|
38
|
+
end
|
46
39
|
|
47
|
-
|
48
|
-
|
40
|
+
def make_http_request(api_request)
|
41
|
+
http_client, http_request = create_http_request(api_request)
|
42
|
+
@client.log(:verbose) { "ApiOperator: Making HTTP Request..." }
|
43
|
+
http_client.request(http_request).tap do |http_response|
|
44
|
+
puts @client.inspect
|
45
|
+
puts http_response.inspect
|
46
|
+
@client.log(:verbose) { "ApiOperator: Response Headers: #{http_response.header.to_yaml}" }
|
47
|
+
end
|
48
|
+
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
def digest_http_response(http_response)
|
51
|
+
@client.api_response_digestor.from_http_response(http_response).tap do |api_response|
|
52
|
+
unless api_response.ok?
|
53
|
+
raise Sevendigital::SevendigitalError.new(api_response.error_code, api_response.error_message), "#{api_response.error_code} - #{api_response.error_message}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
55
57
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
def create_http_request(api_request)
|
59
|
+
http_client, http_request = create_standard_http_request(api_request)
|
60
|
+
if (api_request.requires_signature?)
|
61
|
+
oauth_sign_request(http_client, http_request, api_request)
|
62
|
+
else
|
63
|
+
end
|
64
|
+
[http_client, http_request]
|
61
65
|
end
|
62
|
-
return http_client, http_request
|
63
|
-
end
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
def oauth_sign_request(http_client, http_request, api_request)
|
68
|
+
http_request.oauth!( \
|
69
|
+
http_client, \
|
70
|
+
@client.oauth_consumer, \
|
71
|
+
api_request.token, \
|
72
|
+
{:scheme => api_request.signature_scheme}
|
73
|
+
)
|
74
|
+
http_request
|
75
|
+
end
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
-
|
77
|
+
def create_standard_http_request(api_request)
|
78
|
+
request_uri = create_request_uri(api_request)
|
79
|
+
http_client = Net::HTTP.new(request_uri.host, request_uri.port)
|
78
80
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
if !api_request.requires_signature?
|
82
|
+
request_uri.query ||= ""
|
83
|
+
request_uri.query += "&oauth_consumer_key=#{@client.configuration.oauth_consumer_key}"
|
84
|
+
end
|
83
85
|
|
84
|
-
|
86
|
+
http_request = new_http_request(request_uri.request_uri, api_request.http_method)
|
85
87
|
|
86
|
-
|
87
|
-
|
88
|
+
ensure_secure_connection(http_client) if api_request.requires_secure_connection?
|
89
|
+
add_form_parameters(http_request, api_request)
|
88
90
|
|
89
|
-
|
90
|
-
end
|
91
|
+
@client.log(:verbose) { "ApiOperator: Creating HTTP Request: #{request_uri}" }
|
91
92
|
|
92
|
-
|
93
|
-
|
94
|
-
http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
95
|
-
end
|
93
|
+
[http_client, http_request]
|
94
|
+
end
|
96
95
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
query = api_request.parameters.map{ |k,v| "#{escape(k)}=#{escape(v)}" }.join("&")
|
101
|
-
query = nil if query == ""
|
102
|
-
if api_request.requires_secure_connection? then
|
103
|
-
URI::HTTPS.build(:host => host, :path => path, :query =>query)
|
104
|
-
else
|
105
|
-
URI::HTTP.build(:host => host, :path => path, :query =>query)
|
96
|
+
def ensure_secure_connection(http_client)
|
97
|
+
http_client.use_ssl = true
|
98
|
+
http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
106
99
|
end
|
107
|
-
end
|
108
100
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
101
|
+
def create_request_uri(api_request)
|
102
|
+
host, version = @client.api_host_and_version(api_request.api_service)
|
103
|
+
path = "/#{version}/#{api_request.api_method}"
|
104
|
+
query = api_request.parameters.map{ |k,v| "#{escape(k)}=#{escape(v)}" }.join("&")
|
105
|
+
query = nil if query == ""
|
106
|
+
if api_request.requires_secure_connection? then
|
107
|
+
URI::HTTPS.build(:host => host, :path => path, :query =>query)
|
108
|
+
else
|
109
|
+
URI::HTTP.build(:host => host, :path => path, :query =>query)
|
110
|
+
end
|
111
|
+
end
|
113
112
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
113
|
+
def new_http_request(request_uri, http_method)
|
114
|
+
request_type = Kernel.const_get("Net").const_get("HTTP").const_get(http_method.to_s.capitalize)
|
115
|
+
request_type.new(request_uri, {"user-agent" => @client.user_agent_info})
|
116
|
+
end
|
118
117
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
118
|
+
def add_form_parameters(http_request, api_request)
|
119
|
+
http_request.body = api_request.form_parameters.map {|k, v| "#{escape(k)}=#{escape(v)}" }.flatten.join('&')
|
120
|
+
http_request.content_type = 'application/x-www-form-urlencoded'
|
121
|
+
end
|
124
122
|
|
125
|
-
|
126
|
-
|
123
|
+
def escape(value)
|
124
|
+
URI::escape(value.to_s, RESERVED_CHARACTERS)
|
125
|
+
rescue ArgumentError
|
126
|
+
URI::escape(value.to_s.force_encoding(Encoding::UTF_8), RESERVED_CHARACTERS)
|
127
|
+
end
|
127
128
|
end
|
128
|
-
|
129
129
|
end
|
130
|
-
|
131
|
-
end
|
@@ -1,41 +1,63 @@
|
|
1
1
|
module Sevendigital
|
2
|
+
#@private
|
3
|
+
#Cached version of ApiOperator
|
4
|
+
#If response for an API request is already in cache and
|
5
|
+
#and it hasn't expired returns the cached response is returned instead of making an API call
|
6
|
+
#otherwise uses methods inherited from ApiOperator to make an HTTP call to the API
|
7
|
+
class ApiOperatorCached < ApiOperator # :nodoc:
|
8
|
+
def initialize(client, cache)
|
9
|
+
@cache = cache
|
10
|
+
super(client)
|
11
|
+
end
|
2
12
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
#and it hasn't expired returns the cached response is returned instead of making an API call
|
7
|
-
#otherwise uses methods inherited from ApiOperator to make an HTTP call to the API
|
8
|
-
class ApiOperatorCached < ApiOperator # :nodoc:
|
13
|
+
def call_api(api_request)
|
14
|
+
api_response = retrieve_from_cache(api_request)
|
15
|
+
api_response = cache_response(api_request) if response_out_of_date?(api_response)
|
9
16
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
17
|
+
api_response.tap do |api_response|
|
18
|
+
@client.log(:verbose) { "ApiOperatorCached: API Response: #{api_response}" }
|
19
|
+
end
|
20
|
+
end
|
14
21
|
|
15
|
-
def call_api(api_request)
|
16
|
-
request_cache_key = create_request_uri(api_request)
|
17
|
-
http_response = @cache.get(request_cache_key.to_s) if !api_request.requires_signature?
|
18
|
-
puts "ApiOperatorCached: Got from cache #{request_cache_key}" if @client.verbose? && http_response
|
19
|
-
puts "but the response is out of date" if @client.verbose? && http_response && response_out_of_date?(http_response)
|
20
|
-
if (!http_response || response_out_of_date?(http_response)) then
|
21
|
-
http_response = make_http_request(api_request)
|
22
|
-
@cache.set(request_cache_key.to_s, http_response) if !api_request.requires_signature?
|
23
|
-
end
|
24
|
-
api_response = digest_http_response(http_response)
|
25
|
-
p api_response if @client.very_verbose?
|
26
|
-
api_response
|
27
|
-
end
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
max_age = /max-age=([0-9]+)/.match(http_response.header["cache-control"])[1].to_i
|
36
|
-
response_time + max_age < current_time
|
37
|
-
end
|
23
|
+
def response_out_of_date?(api_response, current_time=nil)
|
24
|
+
puts @client.inspect
|
25
|
+
(api_response.nil? || header_invalid?(api_response.headers) || cache_expired?(api_response.headers, current_time)).tap do |expired|
|
26
|
+
@client.log(:verbose) { "ApiOperatorCached: Cache response out of date" if expired }
|
27
|
+
end
|
28
|
+
end
|
38
29
|
|
39
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
def header_invalid?(header)
|
33
|
+
header["Date"].nil? || header["cache-control"].nil? || !(header["cache-control"] =~ /max-age=([0-9]+)/)
|
34
|
+
end
|
40
35
|
|
36
|
+
def cache_expired?(header, current_time=nil)
|
37
|
+
(Time.parse(header["Date"]) + (/max-age=([0-9]+)/.match(header["cache-control"])[1].to_i)) < (current_time || Time.now.utc)
|
38
|
+
end
|
39
|
+
|
40
|
+
def cache_response(api_request)
|
41
|
+
digest_http_response(make_http_request(api_request)).tap do |api_response|
|
42
|
+
unless api_request.requires_signature?
|
43
|
+
key = request_cache_key(api_request)
|
44
|
+
@cache.respond_to?(:write) ? @cache.write(key, api_response) : @cache.set(key, api_response)
|
45
|
+
@client.log(:verbose) { "ApiOperatorCached: Storing response in cache..." }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def request_cache_key(api_request)
|
51
|
+
create_request_uri(api_request).to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def retrieve_from_cache(api_request)
|
55
|
+
unless api_request.requires_signature?
|
56
|
+
key = request_cache_key(api_request)
|
57
|
+
(@cache.respond_to?(:read) ? @cache.read(key) : @cache.get(key)).tap do |response|
|
58
|
+
@client.log(:verbose) { "ApiOperatorCached: Got from cache #{key}" if response }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
41
63
|
end
|
@@ -1,66 +1,62 @@
|
|
1
1
|
module Sevendigital
|
2
|
+
#@private
|
3
|
+
#Abstraction of a HTTP API request, ApiOperator uses this ApiRequest to build a real HTTP requests
|
4
|
+
class ApiRequest # :nodoc:
|
5
|
+
|
6
|
+
attr_reader :api_method, :parameters, :signed
|
7
|
+
attr_accessor :token, :api_service, :http_method
|
8
|
+
attr_accessor :signature_scheme
|
9
|
+
attr_writer :form_parameters
|
10
|
+
|
11
|
+
def initialize(http_method, api_method, parameters, options={})
|
12
|
+
@api_method = api_method
|
13
|
+
@parameters = parameters
|
14
|
+
@signature_scheme = :header
|
15
|
+
@http_method = http_method
|
16
|
+
comb_parameters(parameters)
|
17
|
+
@form_parameters = Hash.new
|
18
|
+
end
|
2
19
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
attr_reader :api_method, :parameters, :signed
|
8
|
-
attr_accessor :token, :api_service, :http_method
|
9
|
-
attr_accessor :signature_scheme
|
10
|
-
attr_writer :form_parameters
|
11
|
-
|
12
|
-
def initialize(http_method, api_method, parameters, options={})
|
13
|
-
@api_method = api_method
|
14
|
-
@parameters = parameters
|
15
|
-
@signature_scheme = :header
|
16
|
-
@http_method = http_method
|
17
|
-
comb_parameters(parameters)
|
18
|
-
@form_parameters = Hash.new
|
19
|
-
end
|
20
|
-
|
21
|
-
def form_parameters
|
22
|
-
comb_parameters(@form_parameters)
|
23
|
-
end
|
20
|
+
def form_parameters
|
21
|
+
comb_parameters(@form_parameters)
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def requires_signature?
|
25
|
+
@signed == true
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
def require_signature
|
29
|
+
@signed = true
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def requires_secure_connection?
|
33
|
+
@secure == true
|
34
|
+
end
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
def require_secure_connection
|
37
|
+
@secure = true
|
38
|
+
end
|
40
39
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
def comb_parameters(parameters)
|
41
|
+
comb_parameter(parameters, :pageSize, [:page_size, :per_page])
|
42
|
+
comb_parameter(parameters, :shopId, :shop_id)
|
43
|
+
comb_parameter(parameters, :imageSize, :image_size)
|
44
|
+
remove_empty_parameters(parameters)
|
45
|
+
parameters
|
46
|
+
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
48
|
+
def comb_parameter(parameters, correct_name, alternative_names)
|
49
|
+
param_value = nil
|
50
|
+
alternative_names = [alternative_names] unless alternative_names.is_a?(Array)
|
51
|
+
alternative_names.each do |alternative_name|
|
52
|
+
param_value ||= parameters[alternative_name]
|
53
|
+
parameters.delete(alternative_name)
|
54
|
+
end
|
55
|
+
parameters[correct_name] ||= param_value if param_value
|
55
56
|
end
|
56
|
-
parameters[correct_name] ||= param_value if param_value
|
57
|
-
end
|
58
57
|
|
59
|
-
|
60
|
-
|
58
|
+
def remove_empty_parameters(parameters)
|
59
|
+
parameters.delete_if { |key, value| value.nil? }
|
60
|
+
end
|
61
61
|
end
|
62
|
-
|
63
|
-
|
64
62
|
end
|
65
|
-
|
66
|
-
end
|