ac-summarization-utils 0.0.47.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +14 -0
- data/README.md +22 -0
- data/Rakefile +2 -0
- data/ac-summarization-utils.gemspec +24 -0
- data/ac-summarization-utils.iml +28 -0
- data/lib/ac-summarization-utils.rb +8 -0
- data/lib/ac-summarization-utils/errors_handler.rb +77 -0
- data/lib/ac-summarization-utils/general_utils.rb +25 -0
- data/lib/ac-summarization-utils/lookup_cache.rb +480 -0
- data/lib/ac-summarization-utils/record.rb +40 -0
- data/lib/ac-summarization-utils/results_dal.rb +189 -0
- data/lib/ac-summarization-utils/revenue_calc_utils.rb +41 -0
- data/lib/ac-summarization-utils/summarization_utils.rb +119 -0
- data/lib/ac-summarization-utils/validation_utils.rb +93 -0
- data/lib/ac-summarization-utils/version.rb +3 -0
- data/spec/errors_handler_spec.rb +52 -0
- data/spec/general_utils_spec.rb +35 -0
- data/spec/lookup_cache_spec.rb +956 -0
- data/spec/results_dal_spec.rb +349 -0
- data/spec/revenue_calc_utils_spec.rb +125 -0
- data/spec/summarization_utils_spec.rb +210 -0
- data/spec/validation_utils_spec.rb +328 -0
- metadata +116 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
module ACSummarizationUtils
|
3
|
+
|
4
|
+
class Record
|
5
|
+
|
6
|
+
attr_accessor :required_fields
|
7
|
+
attr_accessor :group_fields
|
8
|
+
|
9
|
+
def initialize(input_hash)
|
10
|
+
@required_fields = input_hash[:required] if input_hash[:required]
|
11
|
+
@group_fields = input_hash[:group_fields] if input_hash[:group_fields]
|
12
|
+
@required_fields ||= {}
|
13
|
+
@group_fields ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_required_field(name, value)
|
17
|
+
@required_fields[name] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_group_field(name, value)
|
21
|
+
@group_fields[name] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def clone
|
25
|
+
cloned_record = Record.new({})
|
26
|
+
@required_fields.each do |name, val|
|
27
|
+
cloned_record.add_required_field(name, val)
|
28
|
+
end
|
29
|
+
@group_fields.each do |name, val|
|
30
|
+
cloned_record.add_group_field(name, val)
|
31
|
+
end
|
32
|
+
return cloned_record
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
return (@required_fields == other.required_fields and @group_fields == other.group_fields)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
#insert on duplicate update records to db (using table name, partitions data)
|
2
|
+
require 'mysql2'
|
3
|
+
|
4
|
+
module ACSummarizationUtils
|
5
|
+
class ResultsDAL
|
6
|
+
|
7
|
+
MYSQL_ACTION_TRANSLATOR = {"min" => "LEAST", "max" => "GREATEST" }
|
8
|
+
|
9
|
+
class DBFatalError < RuntimeError; end
|
10
|
+
class InputError < RuntimeError; end
|
11
|
+
class DBUpdateError < RuntimeError
|
12
|
+
attr_accessor :queries, :perform_rollback
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(db_options, table_name, partition_options)
|
16
|
+
begin
|
17
|
+
@mysql_client = Mysql2::Client.new({:host => db_options[:host], :username => db_options[:user], :password => db_options[:password] , :database => db_options[:db_name], :reconnect => true})
|
18
|
+
rescue Exception => e
|
19
|
+
raise DBFatalError, e.message
|
20
|
+
end
|
21
|
+
@table_name = table_name
|
22
|
+
@use_partitions = partition_options.nil? ? false : partition_options[:use_partitions]
|
23
|
+
@bulk_size = (partition_options.nil? or partition_options[:bulk_size].nil?) ? 1 : partition_options[:bulk_size].to_i
|
24
|
+
@use_ids = true
|
25
|
+
@use_ids = partition_options[:use_ids] if !partition_options.nil? and !partition_options[:use_ids].nil?
|
26
|
+
if @use_partitions
|
27
|
+
@partition_field = partition_options[:field_name]
|
28
|
+
@partitions_number = partition_options[:num_partitions].to_i
|
29
|
+
@partition_prefixes = partition_options[:partition_prefixes] if partition_options[:partition_prefixes]
|
30
|
+
@create_tables = (partition_options[:create_tables] ? true : false)
|
31
|
+
@create_table_query = "CREATE TABLE IF NOT EXISTS %TABLE_NAME% " + partition_options[:create_table_columns] if partition_options[:create_table_columns]
|
32
|
+
raise DBFatalError, "Bad partition arguments" if (@partition_field.nil? or @partitions_number.nil? or @partitions_number <= 0 or @partitions_number > 100)
|
33
|
+
else
|
34
|
+
@partitions_number = 1
|
35
|
+
end
|
36
|
+
@use_transactions = db_options[:use_transactions]
|
37
|
+
raise DBFatalError, "Results DB - table #{table_name} doesn't exist!!" unless (table_exists?(table_name) or (@create_tables and @create_table_query))
|
38
|
+
end
|
39
|
+
|
40
|
+
def table_exists?(table_name)
|
41
|
+
begin
|
42
|
+
query = "show tables like '#{table_name}%'"
|
43
|
+
result = @mysql_client.query(query)
|
44
|
+
return (result.nil? or result.size == 0 ? false : true)
|
45
|
+
rescue Exception => e
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def insert_rows(rows, columns ,duplicate_fields, duplicate_fields_actions=nil)
|
51
|
+
return if rows.nil? or rows.empty? or columns.nil? or columns.empty?
|
52
|
+
if duplicate_fields.nil? or duplicate_fields.empty?
|
53
|
+
insert_queries, table_names = generate_unique_queries(rows,columns)
|
54
|
+
else
|
55
|
+
insert_queries, table_names = generate_queries(rows, columns ,duplicate_fields,duplicate_fields_actions)
|
56
|
+
end
|
57
|
+
current_index=0
|
58
|
+
begin
|
59
|
+
if @use_transactions
|
60
|
+
@mysql_client.query("SET AUTOCOMMIT=0")
|
61
|
+
@mysql_client.query("begin")
|
62
|
+
end
|
63
|
+
if (@create_tables)
|
64
|
+
create_tables_if_needed(table_names)
|
65
|
+
end
|
66
|
+
insert_queries.each_with_index do |insert_query,index|
|
67
|
+
current_index = index
|
68
|
+
@mysql_client.query(insert_query[:query])
|
69
|
+
insert_query[:status] = "success"
|
70
|
+
end
|
71
|
+
@mysql_client.query("commit") if @use_transactions
|
72
|
+
rescue Mysql2::Error => e
|
73
|
+
if @use_transactions
|
74
|
+
@mysql_client.query("rollback")
|
75
|
+
raise DBFatalError, "Perfoming rollback - #{e.message}"
|
76
|
+
else
|
77
|
+
db_update_error = DBUpdateError.new e.message
|
78
|
+
insert_queries[current_index][:status] = "failure"
|
79
|
+
db_update_error.queries = insert_queries
|
80
|
+
db_update_error.perform_rollback = false
|
81
|
+
raise db_update_error
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def create_tables_if_needed(table_names)
|
89
|
+
return if @create_table_query.nil?
|
90
|
+
table_names.each do |table_name|
|
91
|
+
create_query = @create_table_query.gsub('%TABLE_NAME%', table_name)
|
92
|
+
@mysql_client.query(create_query)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def generate_unique_queries(rows,columns)
|
97
|
+
insert_value_header = @use_ids ? "(id," : "("
|
98
|
+
|
99
|
+
insert_query_header = "insert into %TABLE_NAME% #{insert_value_header}#{columns.join(',')}) values \n"
|
100
|
+
table_queries, table_names = create_insert_values_per_partition(rows, columns)
|
101
|
+
queries = []
|
102
|
+
|
103
|
+
(0...@partitions_number).each do |part_id|
|
104
|
+
partition_id = @partitions_number > 10 ? '%02d' % part_id : part_id
|
105
|
+
next if table_queries[partition_id].nil?
|
106
|
+
data = table_queries[partition_id]
|
107
|
+
query_header = insert_query_header.gsub('%TABLE_NAME%', data[:table_name])
|
108
|
+
current_size = data[:values].size
|
109
|
+
prev_index = 0
|
110
|
+
while current_size > 0 do
|
111
|
+
current_bulk_values = data[:values].slice(prev_index, @bulk_size).map { |v| v[:value] }
|
112
|
+
queries << {:query=>"#{query_header} #{current_bulk_values.join(',')};",:status=>"not run"}
|
113
|
+
current_size -= @bulk_size
|
114
|
+
prev_index += @bulk_size
|
115
|
+
end
|
116
|
+
end
|
117
|
+
return queries, table_names
|
118
|
+
end
|
119
|
+
|
120
|
+
def generate_queries(rows, columns ,duplicate_fields, duplicate_fields_actions=nil)
|
121
|
+
insert_value_header = @use_ids ? "(id," : "("
|
122
|
+
insert_query_header = "insert into %TABLE_NAME% #{insert_value_header}#{columns.join(',')}) values \n"
|
123
|
+
|
124
|
+
duplicate_values = create_duplicate_values_statement(duplicate_fields,duplicate_fields_actions)
|
125
|
+
queries = []
|
126
|
+
table_queries, table_names = create_insert_values_per_partition(rows, columns)
|
127
|
+
key_columns = columns - duplicate_fields
|
128
|
+
|
129
|
+
(0...@partitions_number).each do |part_id|
|
130
|
+
partition_id = @partitions_number > 10 ? '%02d' % part_id : part_id
|
131
|
+
next if table_queries[partition_id].nil?
|
132
|
+
data = table_queries[partition_id]
|
133
|
+
query_header = insert_query_header.gsub('%TABLE_NAME%', data[:table_name])
|
134
|
+
data[:values].sort_by! {|value| sort_key = []; key_columns.each { |col| sort_key << value[:original_row][col].to_s }; sort_key }
|
135
|
+
current_size = data[:values].size
|
136
|
+
prev_index = 0
|
137
|
+
while current_size > 0 do
|
138
|
+
current_bulk_values = data[:values].slice(prev_index, @bulk_size).map { |v| v[:value] }
|
139
|
+
queries << {:query=>"#{query_header} #{current_bulk_values.join(',')} on duplicate key update #{duplicate_values.join(',')};",:status=>"not run"}
|
140
|
+
current_size -= @bulk_size
|
141
|
+
prev_index += @bulk_size
|
142
|
+
end
|
143
|
+
end
|
144
|
+
return queries, table_names
|
145
|
+
end
|
146
|
+
|
147
|
+
def create_duplicate_values_statement(duplicate_fields,duplicate_fields_actions)
|
148
|
+
duplicate_values = duplicate_fields.map { |f| "#{f} = #{f} + values(#{f})" }
|
149
|
+
duplicate_fields_actions.each do |k,v|
|
150
|
+
if (MYSQL_ACTION_TRANSLATOR.has_key?(v))
|
151
|
+
duplicate_values << "#{k} = #{MYSQL_ACTION_TRANSLATOR[v]}(#{k},values(#{k}))"
|
152
|
+
else
|
153
|
+
sum = "(#{v['SUM']} + values(#{v['SUM']}))"
|
154
|
+
count = "(#{v['COUNT']} + values(#{v['COUNT']}))"
|
155
|
+
duplicate_values << "#{k} = #{sum}/#{count}"
|
156
|
+
end
|
157
|
+
end if !duplicate_fields_actions.nil?
|
158
|
+
return duplicate_values
|
159
|
+
end
|
160
|
+
|
161
|
+
def create_insert_values_per_partition(rows, columns)
|
162
|
+
table_queries = {}
|
163
|
+
partition_id = 0
|
164
|
+
table_names = Set.new
|
165
|
+
new_table_name = @table_name
|
166
|
+
value_header = @use_ids ? "(NULL," : "("
|
167
|
+
rows.each do |row|
|
168
|
+
values_array = columns.map { |c| row[c].nil? ? "NULL" : "'#{row[c].is_a?(String) ? @mysql_client.escape(row[c]) : row[c]}'" }
|
169
|
+
if @use_partitions
|
170
|
+
raise InputError, "Exception in manual partitioning by #{@partition_field} for row" if row[@partition_field].nil?
|
171
|
+
partition_id = row[@partition_field].to_i % @partitions_number
|
172
|
+
partition_id = '%02d' % partition_id if @partitions_number > 10
|
173
|
+
partition_suffix_arr = [partition_id]
|
174
|
+
if @partition_prefixes
|
175
|
+
partition_suffix_arr = @partition_prefixes.map { |prefix| row[prefix].to_s.gsub(/\s+/, '_') unless row[prefix].nil? }
|
176
|
+
partition_suffix_arr << partition_id
|
177
|
+
end
|
178
|
+
|
179
|
+
new_table_name = "#{@table_name}_#{partition_suffix_arr.join('_')}"
|
180
|
+
table_names << new_table_name
|
181
|
+
end
|
182
|
+
table_queries[partition_id] ||= { :table_name => new_table_name, :values => [] }
|
183
|
+
table_queries[partition_id][:values] << {:value =>"#{value_header}#{values_array.join(',')})", :original_row => row}
|
184
|
+
end
|
185
|
+
return table_queries, table_names
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module ACSummarizationUtils
|
4
|
+
module RevenueCalcUtils
|
5
|
+
|
6
|
+
PAYMENT_TYPES = { 1 => :rev_share, 2 => :cpm, 3 => :dynamic, 4 => :geo, 5 => :fixed, 6 => :min_rpc}
|
7
|
+
GEO_COUNTRIES = Set.new ["us"]
|
8
|
+
|
9
|
+
def calc_publisher_click_revenue(revenue, pub_rev_share, pub_payment_type, country)
|
10
|
+
result = 0
|
11
|
+
if should_calc_pub_revenue?(pub_payment_type,country)
|
12
|
+
result = pub_rev_share * revenue
|
13
|
+
end
|
14
|
+
return result
|
15
|
+
end
|
16
|
+
|
17
|
+
def calc_publisher_cpm_revenue(imp_count, pub_cpm_share, pub_payment_type, country)
|
18
|
+
result = 0
|
19
|
+
if !should_calc_pub_revenue?(pub_payment_type,country) or PAYMENT_TYPES[pub_payment_type] == :dynamic
|
20
|
+
result = (pub_cpm_share * imp_count)/1000
|
21
|
+
end
|
22
|
+
return result
|
23
|
+
end
|
24
|
+
|
25
|
+
def calc_publisher_us_click_revenue(cpc,country)
|
26
|
+
return 0 if country.nil?
|
27
|
+
cpc = ((GEO_COUNTRIES.include? country.strip) ? cpc : 0 )
|
28
|
+
return cpc
|
29
|
+
end
|
30
|
+
|
31
|
+
def is_cpm_geo?(country)
|
32
|
+
return false if country.nil?
|
33
|
+
return GEO_COUNTRIES.include? country.strip
|
34
|
+
end
|
35
|
+
|
36
|
+
def should_calc_pub_revenue?(pub_payment_type, country)
|
37
|
+
return (PAYMENT_TYPES[pub_payment_type] == :rev_share or PAYMENT_TYPES[pub_payment_type] == :dynamic or (PAYMENT_TYPES[pub_payment_type] == :geo and !is_cpm_geo?(country)) or PAYMENT_TYPES[pub_payment_type] == :fixed or PAYMENT_TYPES[pub_payment_type] == :min_rpc )
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative 'record'
|
2
|
+
require_relative 'lookup_cache'
|
3
|
+
require_relative 'errors_handler'
|
4
|
+
|
5
|
+
module ACSummarizationUtils
|
6
|
+
module SummUtils
|
7
|
+
|
8
|
+
def initialize_resources(redis_options, lookup_db_options, results_db_options, db_partition_field, db_partition_prefixes=nil)
|
9
|
+
lookup_cache = LookupCache.connect(redis_options, lookup_db_options)
|
10
|
+
results_dal = ResultsDAL.new({:host => results_db_options[:host], :user => results_db_options[:user], :password => results_db_options[:password], :db_name => results_db_options[:name], :use_transactions => results_db_options[:use_transactions]},
|
11
|
+
results_db_options[:table_name],
|
12
|
+
{ :use_partitions => results_db_options[:use_manual_partitions], :field_name => db_partition_field, :num_partitions => results_db_options[:num_partitions], :bulk_size => results_db_options[:bulk_size], :create_tables => results_db_options[:create_tables], :create_table_columns => results_db_options[:create_table_columns], :partition_prefixes => db_partition_prefixes})
|
13
|
+
|
14
|
+
return lookup_cache, results_dal
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_records(logger, error_handler, messages ,&block)
|
18
|
+
if messages and messages.size > 0
|
19
|
+
records = []
|
20
|
+
input_error_messages = []
|
21
|
+
messages.each do |m|
|
22
|
+
begin
|
23
|
+
records.concat(block.call(downcase_hash(m)))
|
24
|
+
rescue LookupCache::InputError, ArgumentError =>e
|
25
|
+
#print_error(logger, "Caught exception of type #{e.class}, exception message - #{e.message}, #{e.backtrace} - sending erroneous message to a different queue")
|
26
|
+
input_error_messages << error_handler.generate_error_message(m,e)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return records, input_error_messages
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#raises an exception if cannot parse date
|
34
|
+
def get_date(date)
|
35
|
+
return nil if date.nil?
|
36
|
+
begin
|
37
|
+
time_object = date.is_a?(Fixnum) ? Time.at(date) : Time.parse(date)
|
38
|
+
return time_object.strftime("%Y-%m-%d")
|
39
|
+
rescue Exception => e
|
40
|
+
raise InputError, "Unable to parse time string: #{date} - message: #{e.message}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#downcase hash keys
|
45
|
+
def downcase_hash(input)
|
46
|
+
return nil if input.nil?
|
47
|
+
result = {}
|
48
|
+
input.each do |k, v|
|
49
|
+
result[k.downcase] = v
|
50
|
+
end
|
51
|
+
return result
|
52
|
+
end
|
53
|
+
|
54
|
+
#duplicate records according to specific field values
|
55
|
+
def duplicate_records(current_records, field, expanded_field_values)
|
56
|
+
return current_records if current_records.nil? or current_records.size == 0 or field.nil? or expanded_field_values.nil? or expanded_field_values.size == 0
|
57
|
+
additional_records = []
|
58
|
+
current_records.each do |new_record|
|
59
|
+
new_record.add_required_field(field, expanded_field_values.first)
|
60
|
+
expanded_field_values[1..-1].each do |expanded_value|
|
61
|
+
cloned_record = new_record.clone
|
62
|
+
cloned_record.add_required_field(field, expanded_value)
|
63
|
+
additional_records << cloned_record
|
64
|
+
end
|
65
|
+
end
|
66
|
+
current_records += additional_records
|
67
|
+
return current_records
|
68
|
+
end
|
69
|
+
|
70
|
+
#group_options is a array of this form: [ {:output_field_name => "", :method => "" , :input_field_name => "" }]
|
71
|
+
#example: [ {:output_field_name => "spend", :method => method(:sum), :input_field_name => "cpc"}]
|
72
|
+
def summarize_records(records, group_options)
|
73
|
+
return [] if records.nil? or records.empty?
|
74
|
+
unified_records = {}
|
75
|
+
records.each do |record|
|
76
|
+
unified_key = record.required_fields.to_a.join(";")
|
77
|
+
unified_records[unified_key] ||= record.required_fields
|
78
|
+
group_options.each do |group_operation|
|
79
|
+
group_operation[:method].call(unified_records[unified_key], record, group_operation[:input_field_name], group_operation[:output_field_name])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return unified_records.values
|
83
|
+
end
|
84
|
+
|
85
|
+
def sum(unified_record, record, input_field_name, output_field_name)
|
86
|
+
raise ArgumentError, "Unsupported field name for group function: #{input_field_name}" if record.group_fields[input_field_name].nil?
|
87
|
+
unified_record[output_field_name] ||= 0
|
88
|
+
unified_record[output_field_name] += record.group_fields[input_field_name].to_f
|
89
|
+
end
|
90
|
+
|
91
|
+
def count(unified_record, record, input_field_name, output_field_name)
|
92
|
+
raise ArgumentError, "Unsupported field name for group function: #{input_field_name}" if record.group_fields[input_field_name].nil?
|
93
|
+
unified_record[output_field_name] ||= 0
|
94
|
+
unified_record[output_field_name] += 1 if record.group_fields[input_field_name]
|
95
|
+
end
|
96
|
+
|
97
|
+
def minimum(unified_record, record, input_field_name, output_field_name)
|
98
|
+
raise ArgumentError, "Unsupported field name for group function: #{input_field_name}" if record.group_fields[input_field_name].nil?
|
99
|
+
unified_record[output_field_name] ||= 1000
|
100
|
+
unified_record[output_field_name] = [unified_record[output_field_name].to_f,record.group_fields[input_field_name].to_f].min
|
101
|
+
end
|
102
|
+
|
103
|
+
def maximum(unified_record, record, input_field_name, output_field_name)
|
104
|
+
raise ArgumentError, "Unsupported field name for group function: #{input_field_name}" if record.group_fields[input_field_name].nil?
|
105
|
+
unified_record[output_field_name] ||= 0
|
106
|
+
unified_record[output_field_name] = [unified_record[output_field_name].to_f,record.group_fields[input_field_name].to_f].max
|
107
|
+
end
|
108
|
+
|
109
|
+
def average(unified_record, record, input_field_name, output_field_name)
|
110
|
+
raise ArgumentError, "Unsupported field name for group function: #{input_field_name}" if record.group_fields[input_field_name].nil?
|
111
|
+
unified_record[output_field_name] ||= 0
|
112
|
+
sum(unified_record,record,input_field_name,output_field_name+"_sum")
|
113
|
+
count(unified_record,record,input_field_name,output_field_name+"_count")
|
114
|
+
unified_record[output_field_name] ||= 0
|
115
|
+
unified_record[output_field_name] = (( unified_record[output_field_name+"_count"] > 0 ) ? (unified_record[output_field_name+"_sum"] / unified_record[output_field_name+"_count"]) : 0.0 )
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
module ACSummarizationUtils
|
3
|
+
module ValidationUtils
|
4
|
+
|
5
|
+
ALLOWED_CLICK_TYPES = [1, 2, 5, 6, 1005]
|
6
|
+
REAL_CLICKS = [1, 3, 5, 11, 107, 108, 801, 805]
|
7
|
+
INVALID_CLICK_TYPE = -1
|
8
|
+
CPC = 1
|
9
|
+
CPV = 3
|
10
|
+
|
11
|
+
def common_click_validations(message)
|
12
|
+
click_type = message["clicktype"].nil? ? message["ct"] : message["clicktype"]
|
13
|
+
return [INVALID_CLICK_TYPE, -1] if click_type.to_s.empty? and (message["clickurl"].to_s.empty? or message["clickurl"] == 'NULL')
|
14
|
+
raise ArgumentError, "message required field click_type not ct doesn't exist" if click_type.nil?
|
15
|
+
valid = message["valid"].nil? ? message["validitytype"] : message["valid"]
|
16
|
+
raise ArgumentError, "message required field valid not validitytype doesn't exist" if valid.nil?
|
17
|
+
["ad_id","advertiser_id","cpc"].each do |field_name|
|
18
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if message[field_name].nil?
|
19
|
+
end
|
20
|
+
raise ArgumentError, "invalid ad id: #{message["ad_id"]}" unless message["ad_id"].to_s =~ /^[-]?[0-9]+$/
|
21
|
+
[click_type,valid]
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_valid_real_click?(message, campaign_type)
|
25
|
+
click_type, valid = common_click_validations(message)
|
26
|
+
if (REAL_CLICKS.include?(click_type.to_i) or (1005 == click_type.to_i and campaign_type.to_i == CPC))
|
27
|
+
return (message["ad_id"].to_i != -1 and message["advertiser_id"].to_i == 8 and valid.to_i == 1)
|
28
|
+
end
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
def is_valid_direct_click?(message)
|
33
|
+
click_type, valid = common_click_validations(message)
|
34
|
+
return (message["ad_id"].to_i != -1 and message["advertiser_id"].to_i == 8 and valid.to_i == 1 and
|
35
|
+
message["cpc"].to_f >= 0.0 and ALLOWED_CLICK_TYPES.include?(click_type.to_i))
|
36
|
+
end
|
37
|
+
|
38
|
+
def is_valid_direct_layer_impr?(message)
|
39
|
+
["ad_id","advertiserid"].each do |field_name|
|
40
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if message[field_name].nil?
|
41
|
+
end
|
42
|
+
return (message["ad_id"].to_i != -1 and message["advertiserid"].to_i == 8)
|
43
|
+
end
|
44
|
+
|
45
|
+
def is_valid_conversion?(message)
|
46
|
+
["adid","conversioneventid","publisherid"].each do |field_name|
|
47
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if message[field_name].nil?
|
48
|
+
end
|
49
|
+
return (message["adid"].to_i != -1 and message["conversioneventid"].to_i > 0)
|
50
|
+
end
|
51
|
+
|
52
|
+
def is_valid_dynamic_content_event?(message)
|
53
|
+
["cid"].each do |field_name|
|
54
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if message[field_name].nil?
|
55
|
+
end
|
56
|
+
return (message["cid"].to_i != -1)
|
57
|
+
end
|
58
|
+
|
59
|
+
def is_valid_layer_impr?(message)
|
60
|
+
["ad_id","advertiserid","cpc"].each do |field_name|
|
61
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if message[field_name].nil?
|
62
|
+
end
|
63
|
+
return message["cpc"].to_f >= 0.0
|
64
|
+
end
|
65
|
+
|
66
|
+
def is_valid_click?(message)
|
67
|
+
click_type, valid = common_click_validations(message)
|
68
|
+
publisher_field = message["publisher_id"] || message["p"]
|
69
|
+
raise ArgumentError, "message required field 'publisher_id' or 'p' doesn't exist" if publisher_field.nil?
|
70
|
+
|
71
|
+
return ( valid.to_i == 1 and message["cpc"].to_f >= 0.0 and ALLOWED_CLICK_TYPES.include?(click_type.to_i))
|
72
|
+
end
|
73
|
+
|
74
|
+
def is_valid_impression?(message)
|
75
|
+
["pid", "itid"].each do |field_name|
|
76
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if message[field_name].nil?
|
77
|
+
end
|
78
|
+
return message["itid"].to_i == 3
|
79
|
+
end
|
80
|
+
|
81
|
+
def is_valid_inimage_report?(message)
|
82
|
+
["value"].each do |field_name|
|
83
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if message[field_name].nil?
|
84
|
+
end
|
85
|
+
value = message["value"]
|
86
|
+
["account_id"].each do |field_name|
|
87
|
+
raise ArgumentError, "message required field '#{field_name}' doesn't exist" if value[field_name].nil?
|
88
|
+
end
|
89
|
+
return message["value"]["account_id"] != ""
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|