appnexusapi 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +71 -39
- data/appnexusapi.gemspec +1 -2
- data/lib/appnexusapi.rb +21 -10
- data/lib/appnexusapi/configuration.rb +12 -0
- data/lib/appnexusapi/connection.rb +83 -90
- data/lib/appnexusapi/error.rb +3 -0
- data/lib/appnexusapi/faraday/raise_http_error.rb +15 -1
- data/lib/appnexusapi/read_only_service.rb +8 -0
- data/lib/appnexusapi/resource.rb +19 -15
- data/lib/appnexusapi/service.rb +35 -48
- data/lib/appnexusapi/services/ad_server_service.rb +9 -0
- data/lib/appnexusapi/{advertiser_service.rb → services/advertiser_service.rb} +0 -0
- data/lib/appnexusapi/{bidder_instance_service.rb → services/bidder_instance_service.rb} +0 -6
- data/lib/appnexusapi/{bidder_profile_service.rb → services/bidder_profile_service.rb} +0 -6
- data/lib/appnexusapi/{bidder_service.rb → services/bidder_service.rb} +0 -0
- data/lib/appnexusapi/services/brand_service.rb +2 -0
- data/lib/appnexusapi/services/browser_service.rb +2 -0
- data/lib/appnexusapi/{campaign_service.rb → services/campaign_service.rb} +0 -0
- data/lib/appnexusapi/services/category_service.rb +5 -0
- data/lib/appnexusapi/{content_category_service.rb → services/content_category_service.rb} +0 -1
- data/lib/appnexusapi/{creative_service.rb → services/creative_service.rb} +0 -0
- data/lib/appnexusapi/{creative_template_service.rb → services/creative_template_service.rb} +1 -6
- data/lib/appnexusapi/services/device_model_service.rb +2 -0
- data/lib/appnexusapi/{domain_list_service.rb → services/domain_list_service.rb} +0 -0
- data/lib/appnexusapi/services/inventory_attribute_service.rb +2 -0
- data/lib/appnexusapi/{inventory_source_service.rb → services/inventory_source_service.rb} +0 -0
- data/lib/appnexusapi/services/language_service.rb +2 -0
- data/lib/appnexusapi/{line_item_service.rb → services/line_item_service.rb} +0 -0
- data/lib/appnexusapi/services/log_level_data_download_service.rb +13 -0
- data/lib/appnexusapi/services/log_level_data_service.rb +105 -0
- data/lib/appnexusapi/services/media_type_service.rb +2 -0
- data/lib/appnexusapi/{member_service.rb → services/member_service.rb} +0 -0
- data/lib/appnexusapi/{object_limit_service.rb → services/object_limit_service.rb} +0 -0
- data/lib/appnexusapi/{operating_system_extended_service.rb → services/operating_system_extended_service.rb} +1 -6
- data/lib/appnexusapi/services/operating_system_service.rb +2 -0
- data/lib/appnexusapi/{payment_rule_service.rb → services/payment_rule_service.rb} +0 -0
- data/lib/appnexusapi/{placement_service.rb → services/placement_service.rb} +0 -0
- data/lib/appnexusapi/services/platform_member_service.rb +2 -0
- data/lib/appnexusapi/{profile_service.rb → services/profile_service.rb} +0 -0
- data/lib/appnexusapi/{publisher_service.rb → services/publisher_service.rb} +0 -0
- data/lib/appnexusapi/{segment_service.rb → services/segment_service.rb} +0 -2
- data/lib/appnexusapi/{site_service.rb → services/site_service.rb} +0 -0
- data/lib/appnexusapi/services/technical_attribute_service.rb +2 -0
- data/lib/appnexusapi/{tiny_tag_service.rb → services/tiny_tag_service.rb} +0 -6
- data/lib/appnexusapi/{user_service.rb → services/user_service.rb} +0 -0
- data/lib/appnexusapi/version.rb +1 -1
- data/spec/connection_spec.rb +46 -10
- data/spec/fixtures/vcr/content_category_crud.yml +188 -69
- data/spec/fixtures/vcr/log_level_data_service_download.yml +213 -0
- data/spec/integration/content_category_spec.rb +4 -0
- data/spec/{creative_service_spec.rb → integration/creative_service_spec.rb} +0 -0
- data/spec/integration/log_level_data_service_spec.rb +13 -0
- data/spec/{object_limit_service_spec.rb → integration/object_limit_service_spec.rb} +0 -0
- data/spec/integration/placement_spec.rb +0 -1
- data/spec/spec_helper.rb +2 -3
- metadata +52 -94
- data/lib/appnexusapi/ad_server_resource.rb +0 -2
- data/lib/appnexusapi/ad_server_service.rb +0 -20
- data/lib/appnexusapi/advertiser_resource.rb +0 -2
- data/lib/appnexusapi/bidder_instance_resource.rb +0 -2
- data/lib/appnexusapi/bidder_profile_resource.rb +0 -2
- data/lib/appnexusapi/bidder_resource.rb +0 -2
- data/lib/appnexusapi/brand_resource.rb +0 -2
- data/lib/appnexusapi/brand_service.rb +0 -8
- data/lib/appnexusapi/browser_resource.rb +0 -2
- data/lib/appnexusapi/browser_service.rb +0 -8
- data/lib/appnexusapi/campaign_resource.rb +0 -2
- data/lib/appnexusapi/category_resource.rb +0 -2
- data/lib/appnexusapi/category_service.rb +0 -12
- data/lib/appnexusapi/content_category_resource.rb +0 -2
- data/lib/appnexusapi/creative_resource.rb +0 -2
- data/lib/appnexusapi/creative_template_resource.rb +0 -2
- data/lib/appnexusapi/device_model_resource.rb +0 -2
- data/lib/appnexusapi/device_model_service.rb +0 -6
- data/lib/appnexusapi/domain_list_resource.rb +0 -2
- data/lib/appnexusapi/inventory_attribute_resource.rb +0 -2
- data/lib/appnexusapi/inventory_attribute_service.rb +0 -8
- data/lib/appnexusapi/inventory_source_resource.rb +0 -2
- data/lib/appnexusapi/language_resource.rb +0 -2
- data/lib/appnexusapi/language_service.rb +0 -8
- data/lib/appnexusapi/line_item_resource.rb +0 -2
- data/lib/appnexusapi/log_level_data_download_service.rb +0 -68
- data/lib/appnexusapi/log_level_data_resource.rb +0 -19
- data/lib/appnexusapi/log_level_data_service.rb +0 -26
- data/lib/appnexusapi/media_type_resource.rb +0 -2
- data/lib/appnexusapi/media_type_service.rb +0 -8
- data/lib/appnexusapi/member_resource.rb +0 -2
- data/lib/appnexusapi/object_limit_resource.rb +0 -2
- data/lib/appnexusapi/operating_system_extended_resource.rb +0 -2
- data/lib/appnexusapi/operating_system_resource.rb +0 -2
- data/lib/appnexusapi/operating_system_service.rb +0 -8
- data/lib/appnexusapi/payment_rule_resource.rb +0 -2
- data/lib/appnexusapi/placement_resource.rb +0 -2
- data/lib/appnexusapi/platform_member_resource.rb +0 -2
- data/lib/appnexusapi/platform_member_service.rb +0 -8
- data/lib/appnexusapi/profile_resource.rb +0 -2
- data/lib/appnexusapi/publisher_resource.rb +0 -2
- data/lib/appnexusapi/segment_resource.rb +0 -2
- data/lib/appnexusapi/site_resource.rb +0 -2
- data/lib/appnexusapi/technical_attribute_resource.rb +0 -2
- data/lib/appnexusapi/technical_attribute_service.rb +0 -8
- data/lib/appnexusapi/tiny_tag_resource.rb +0 -2
- data/lib/appnexusapi/user_resource.rb +0 -2
data/lib/appnexusapi/resource.rb
CHANGED
@@ -1,39 +1,43 @@
|
|
1
1
|
class AppnexusApi::Resource
|
2
2
|
|
3
|
-
attr_reader :dbg_info
|
3
|
+
attr_reader :dbg_info, :raw_json
|
4
4
|
|
5
5
|
def initialize(json, service, dbg_info = nil)
|
6
|
-
@
|
6
|
+
@raw_json = json
|
7
7
|
@service = service
|
8
8
|
@dbg_info = dbg_info
|
9
9
|
end
|
10
10
|
|
11
|
-
def update(route_params={}, body_params={})
|
12
|
-
|
13
|
-
@json = resource.raw_json
|
11
|
+
def update(route_params = {}, body_params = {})
|
12
|
+
@raw_json = @service.update(id, route_params, body_params).raw_json
|
14
13
|
self
|
15
14
|
end
|
16
15
|
|
17
|
-
|
18
|
-
|
16
|
+
# If you have modified the @raw_json hash in place, you can just do resource.save
|
17
|
+
def save
|
18
|
+
@service.update(id, {}, @raw_json).raw_json
|
19
|
+
self
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
-
@
|
22
|
+
def delete(route_params = {})
|
23
|
+
@service.delete(id, route_params)
|
23
24
|
end
|
24
25
|
|
25
26
|
def method_missing(sym, *args, &block)
|
26
|
-
if @
|
27
|
-
@
|
28
|
-
elsif @
|
29
|
-
|
27
|
+
if @raw_json.respond_to?(sym)
|
28
|
+
@raw_json.send(sym, *args, &block)
|
29
|
+
elsif @raw_json.key?(sym.to_s)
|
30
|
+
@raw_json[sym.to_s]
|
30
31
|
else
|
31
32
|
super(sym, *args, &block)
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
|
-
def
|
36
|
-
@
|
36
|
+
def respond_to_missing?(method_name, include_private = false)
|
37
|
+
@raw_json.respond_to?(method_name) || @raw_json.key?(method_name.to_s) || super
|
37
38
|
end
|
38
39
|
|
40
|
+
def to_s
|
41
|
+
@raw_json.inspect
|
42
|
+
end
|
39
43
|
end
|
data/lib/appnexusapi/service.rb
CHANGED
@@ -7,7 +7,7 @@ class AppnexusApi::Service
|
|
7
7
|
|
8
8
|
def name
|
9
9
|
@name ||= begin
|
10
|
-
str = self.class.name.split(
|
10
|
+
str = self.class.name.split('::').last.sub(/Service\z/, '')
|
11
11
|
str.gsub(/(.)([A-Z])/, '\1_\2').downcase
|
12
12
|
end
|
13
13
|
end
|
@@ -16,13 +16,6 @@ class AppnexusApi::Service
|
|
16
16
|
name + 's'
|
17
17
|
end
|
18
18
|
|
19
|
-
def resource_class
|
20
|
-
@resource_class ||= begin
|
21
|
-
resource_name = name.capitalize.gsub(/(_(.))/) { |c| $2.upcase }
|
22
|
-
AppnexusApi.const_get(resource_name + "Resource")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
19
|
def uri_name
|
27
20
|
name.gsub('_', '-')
|
28
21
|
end
|
@@ -35,20 +28,12 @@ class AppnexusApi::Service
|
|
35
28
|
uri_name
|
36
29
|
end
|
37
30
|
|
38
|
-
def get(params={})
|
39
|
-
|
40
|
-
params
|
41
|
-
"num_elements" => DEFAULT_NUMBER_OF_ELEMENTS,
|
42
|
-
"start_element" => 0
|
43
|
-
}.merge(params)
|
44
|
-
response = @connection.get(uri_suffix, params).body['response']
|
45
|
-
if return_response
|
46
|
-
response
|
47
|
-
else
|
48
|
-
parse_response(response)
|
49
|
-
end
|
31
|
+
def get(params = {})
|
32
|
+
params = { 'num_elements' => DEFAULT_NUMBER_OF_ELEMENTS, 'start_element' => 0 }.merge(params)
|
33
|
+
parse_response(@connection.get(uri_suffix, params).body['response'])
|
50
34
|
end
|
51
35
|
|
36
|
+
# Page through all available elements automatically
|
52
37
|
def get_all(params = {})
|
53
38
|
responses = []
|
54
39
|
last_responses = get(params)
|
@@ -61,54 +46,56 @@ class AppnexusApi::Service
|
|
61
46
|
responses
|
62
47
|
end
|
63
48
|
|
64
|
-
def create(route_params={}, body={})
|
65
|
-
|
66
|
-
body = { uri_name => body }
|
49
|
+
def create(route_params = {}, body = {})
|
50
|
+
check_read_only!
|
67
51
|
route = @connection.build_url(uri_suffix, route_params)
|
68
|
-
response = @connection.post(route, body).body['response']
|
69
|
-
|
70
|
-
|
71
|
-
raise AppnexusApi::BadRequest.new(response.inspect)
|
72
|
-
end
|
52
|
+
response = @connection.post(route, { uri_name => body }).body['response']
|
53
|
+
validate_response!(response)
|
54
|
+
|
73
55
|
parse_response(response).first
|
74
56
|
end
|
75
57
|
|
76
|
-
def update(id, route_params={}, body={})
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
response
|
81
|
-
|
82
|
-
response.delete('dbg')
|
83
|
-
raise AppnexusApi::BadRequest.new(response.inspect)
|
84
|
-
end
|
58
|
+
def update(id, route_params = {}, body = {})
|
59
|
+
check_read_only!
|
60
|
+
route = @connection.build_url(uri_suffix, route_params.merge('id' => id))
|
61
|
+
response = @connection.put(route, { uri_name => body }).body['response']
|
62
|
+
validate_response!(response)
|
63
|
+
|
85
64
|
parse_response(response).first
|
86
65
|
end
|
87
66
|
|
88
67
|
def delete(id, route_params)
|
89
|
-
|
90
|
-
route = @connection.build_url(uri_suffix, route_params.merge(
|
68
|
+
check_read_only!
|
69
|
+
route = @connection.build_url(uri_suffix, route_params.merge('id' => id))
|
91
70
|
response = @connection.delete(route).body['response']
|
92
|
-
|
93
|
-
|
94
|
-
raise AppnexusApi::BadRequest.new(response.inspect)
|
95
|
-
end
|
71
|
+
validate_response!(response)
|
72
|
+
|
96
73
|
response
|
97
74
|
end
|
98
75
|
|
76
|
+
private
|
77
|
+
|
78
|
+
def check_read_only!
|
79
|
+
raise(AppnexusApi::NotImplemented, "Service is read-only.") if @read_only
|
80
|
+
end
|
81
|
+
|
82
|
+
def validate_response!(response)
|
83
|
+
return unless response['error_id']
|
84
|
+
|
85
|
+
response.delete('dbg')
|
86
|
+
raise AppnexusApi::BadRequest.new(response.inspect)
|
87
|
+
end
|
88
|
+
|
99
89
|
def parse_response(response)
|
100
90
|
case key = resource_name(response)
|
101
91
|
when plural_name, plural_uri_name
|
102
|
-
response[key].map
|
103
|
-
resource_class.new(json, self, response['dbg'])
|
104
|
-
end
|
92
|
+
response[key].map { |json| AppnexusApi::Resource.new(json, self, response['dbg']) }
|
105
93
|
when name, uri_name
|
106
|
-
[
|
94
|
+
[AppnexusApi::Resource.new(response[key], self, response['dbg'])]
|
107
95
|
end
|
108
96
|
end
|
109
97
|
|
110
98
|
def resource_name(response)
|
111
99
|
[plural_name, plural_uri_name, name, uri_name].detect { |n| response.key?(n) }
|
112
100
|
end
|
113
|
-
|
114
101
|
end
|
File without changes
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class AppnexusApi::BidderInstanceService < AppnexusApi::Service
|
2
|
-
|
3
2
|
def initialize(connection, bidder_id)
|
4
3
|
@bidder_id = bidder_id
|
5
4
|
super(connection)
|
@@ -9,10 +8,6 @@ class AppnexusApi::BidderInstanceService < AppnexusApi::Service
|
|
9
8
|
"instance"
|
10
9
|
end
|
11
10
|
|
12
|
-
def resource_class
|
13
|
-
AppnexusApi::BidderInstanceResource
|
14
|
-
end
|
15
|
-
|
16
11
|
def uri_suffix
|
17
12
|
"bidder-instance/#{@bidder_id}"
|
18
13
|
end
|
@@ -20,5 +15,4 @@ class AppnexusApi::BidderInstanceService < AppnexusApi::Service
|
|
20
15
|
def delete(id)
|
21
16
|
raise AppnexusApi::NotImplemented, "To remove an instance, please set it to inactive."
|
22
17
|
end
|
23
|
-
|
24
18
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class AppnexusApi::BidderProfileService < AppnexusApi::Service
|
2
|
-
|
3
2
|
def initialize(connection, bidder_id)
|
4
3
|
@bidder_id = bidder_id
|
5
4
|
super(connection)
|
@@ -9,10 +8,6 @@ class AppnexusApi::BidderProfileService < AppnexusApi::Service
|
|
9
8
|
"profile"
|
10
9
|
end
|
11
10
|
|
12
|
-
def resource_class
|
13
|
-
AppnexusApi::BidderProfileResource
|
14
|
-
end
|
15
|
-
|
16
11
|
def uri_suffix
|
17
12
|
"profile/#{@bidder_id}"
|
18
13
|
end
|
@@ -20,5 +15,4 @@ class AppnexusApi::BidderProfileService < AppnexusApi::Service
|
|
20
15
|
def delete(id)
|
21
16
|
raise AppnexusApi::NotImplemented
|
22
17
|
end
|
23
|
-
|
24
18
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -3,16 +3,11 @@ class AppnexusApi::CreativeTemplateService < AppnexusApi::Service
|
|
3
3
|
"template"
|
4
4
|
end
|
5
5
|
|
6
|
-
def resource_class
|
7
|
-
AppnexusApi::CreativeTemplateResource
|
8
|
-
end
|
9
|
-
|
10
6
|
def uri_suffix
|
11
|
-
|
7
|
+
name
|
12
8
|
end
|
13
9
|
|
14
10
|
def delete(id)
|
15
11
|
raise AppnexusApi::NotImplemented
|
16
12
|
end
|
17
|
-
|
18
13
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'appnexusapi/services/log_level_data_service'
|
2
|
+
|
3
|
+
# TODO: Remove this class in v2.0
|
4
|
+
module AppnexusApi
|
5
|
+
class LogLevelDataDownloadService < LogLevelDataService
|
6
|
+
extend Gem::Deprecate
|
7
|
+
|
8
|
+
def initialize(connection, options = {})
|
9
|
+
super
|
10
|
+
end
|
11
|
+
deprecate :initialize, 'LogLevelDataService#initialize', 2017, 6
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module AppnexusApi
|
2
|
+
class LogLevelDataService < AppnexusApi::ReadOnlyService
|
3
|
+
DEFAULT_FEED = 'standard_feed'.freeze
|
4
|
+
DOWNLOAD_URI = 'siphon-download'.freeze
|
5
|
+
RETRY_DOWNLOAD_PARAMS = {
|
6
|
+
base_interval: 30,
|
7
|
+
tries: 20,
|
8
|
+
max_elapsed_time: 3600,
|
9
|
+
on: [AppnexusApi::Error, ::Faraday::Error::ClientError],
|
10
|
+
on_retry: Proc.new do |exception, tries|
|
11
|
+
AppnexusApi.config.logger.warn("Retrying after #{exception.class}: #{tries} attempts.")
|
12
|
+
end
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def initialize(connection, options = {})
|
16
|
+
@downloaded_files_path = options[:downloaded_files_path] || '.'
|
17
|
+
@siphon_name = options[:siphon_name] || DEFAULT_FEED
|
18
|
+
super(connection)
|
19
|
+
end
|
20
|
+
|
21
|
+
def download_new_files_since(time = nil)
|
22
|
+
since(time).map { |siphon| download_resource(siphon) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def uri_name
|
26
|
+
'siphon'
|
27
|
+
end
|
28
|
+
|
29
|
+
def since(time = nil)
|
30
|
+
params = {}
|
31
|
+
params[:siphon_name] = @siphon_name if @siphon_name
|
32
|
+
params[:updated_since] = time.strftime('%Y_%m_%d_%H') if time
|
33
|
+
siphons = get(params) || {}
|
34
|
+
|
35
|
+
# Anything with the same name and hour but with a newer timestamp is a republished replacement for an older file.
|
36
|
+
# When this happens appnexus is supposed to set the checksum for the old file to NULL but they do not always
|
37
|
+
# actually do this, so we have to manually reject invalid entries.
|
38
|
+
siphons.reject do |siphon|
|
39
|
+
(siphons - [siphon]).any? { |s| s.name == siphon.name && s.hour == siphon.hour && s.timestamp > siphon.timestamp }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Parameter is a LogLevelDataResource FKA a "Siphon"
|
46
|
+
# Downloads a gzipped file
|
47
|
+
# Returns an array of paths to downloaded files
|
48
|
+
def download_resource(siphon)
|
49
|
+
fail 'Missing necessary information!' unless siphon.name && siphon.hour && siphon.timestamp && siphon.splits
|
50
|
+
|
51
|
+
download_params = siphon.splits.map do |split_part|
|
52
|
+
# In the case of files that were later replaced, there should be no checksum and they shouldn't be downloaded
|
53
|
+
next nil if split_part['checksum'].nil? || split_part['checksum'].empty?
|
54
|
+
|
55
|
+
{
|
56
|
+
split_part: split_part['part'],
|
57
|
+
siphon_name: siphon.name,
|
58
|
+
timestamp: siphon.timestamp,
|
59
|
+
hour: siphon.hour,
|
60
|
+
checksum: split_part['checksum']
|
61
|
+
}
|
62
|
+
end.compact
|
63
|
+
|
64
|
+
download_params.map do |params|
|
65
|
+
uri = URI.parse(@connection.get(DOWNLOAD_URI, params.reject { |k, v| k == :checksum }).headers['location'])
|
66
|
+
filename = File.join(@downloaded_files_path, "#{params[:siphon_name]}_#{params[:hour]}_#{params[:split_part]}.gz")
|
67
|
+
|
68
|
+
Retriable.retriable(RETRY_DOWNLOAD_PARAMS) do
|
69
|
+
download_file(uri, filename)
|
70
|
+
calculated_checksum = Digest::MD5.hexdigest(File.read(filename))
|
71
|
+
if calculated_checksum != params[:checksum]
|
72
|
+
error_message = "Calculated checksum of #{calculated_checksum} doesn't match API provided checksum #{params[:checksum]}"
|
73
|
+
AppnexusApi.config.logger.fatal(error_message)
|
74
|
+
raise BadChecksumException, error_message
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
filename
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def download_file(uri, filename)
|
83
|
+
AppnexusApi.config.logger.debug("Starting HTTP download for: #{uri.to_s}...")
|
84
|
+
http_object = Net::HTTP.new(uri.host, uri.port)
|
85
|
+
http_object.use_ssl = true if uri.scheme == 'https'
|
86
|
+
|
87
|
+
begin
|
88
|
+
http_object.start do |http|
|
89
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
90
|
+
http.read_timeout = 500
|
91
|
+
|
92
|
+
http.request(request) do |response|
|
93
|
+
open(filename, 'wb') do |io|
|
94
|
+
response.read_body do |chunk|
|
95
|
+
io.write(chunk)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
AppnexusApi.config.logger.info("Stored download of #{uri.to_s} as #{filename}")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|