sklik-api 0.0.16 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +28 -4
- data/VERSION +1 -1
- data/lib/sklik-api/campaign.rb +112 -67
- data/lib/sklik-api/campaign_parts/adgroup.rb +272 -95
- data/lib/sklik-api/campaign_parts/adtext.rb +165 -31
- data/lib/sklik-api/campaign_parts/keyword.rb +192 -38
- data/lib/sklik-api/client.rb +4 -4
- data/lib/sklik-api/connection.rb +36 -13
- data/lib/sklik-api/exceptions.rb +6 -0
- data/lib/sklik-api/sklik_object.rb +29 -1
- data/lib/sklik-api.rb +20 -3
- data/sklik-api.gemspec +11 -3
- data/test/integration/adgroup_test.rb +126 -0
- data/test/integration/adtext_test.rb +106 -0
- data/test/integration/campaign_test.rb +87 -0
- data/test/integration/errors_test.rb +164 -0
- data/test/integration/keyword_test.rb +131 -0
- data/test/unit/adgroup_test.rb +147 -0
- data/test/unit/campaign_test.rb +318 -0
- data/test/unit/client_test.rb +27 -0
- metadata +12 -4
- data/test/unit/campaign.rb +0 -180
@@ -4,7 +4,7 @@ class SklikApi
|
|
4
4
|
|
5
5
|
NAME = "group"
|
6
6
|
|
7
|
-
include
|
7
|
+
include SklikObject
|
8
8
|
=begin
|
9
9
|
Example of input hash
|
10
10
|
{
|
@@ -30,47 +30,121 @@ Example of input hash
|
|
30
30
|
|
31
31
|
=end
|
32
32
|
|
33
|
-
def initialize
|
33
|
+
def initialize args, deprecated_args = {}
|
34
|
+
|
35
|
+
#deprecated way to set up new adgroup!
|
36
|
+
if args.is_a?(SklikApi::Campaign)
|
37
|
+
puts "DEPRECATION WARNING: Please update your code for SklikApi::Adgroup.new(campaign, args) to SklikApi::Adgroup.new(args = {}) possible to add parent camapign by adding :campaign => your campaign"
|
38
|
+
#set adgroup owner campaign
|
39
|
+
@campaign = args
|
40
|
+
args = deprecated_args
|
41
|
+
|
42
|
+
#new way to set adgroups!
|
43
|
+
else
|
44
|
+
#set adgroup owner campaign
|
45
|
+
#if in input args there is pointer to parent campaign!
|
46
|
+
if @campaign = args.delete(:campaign)
|
47
|
+
# if no cpc was given - try to use campaign cpc
|
48
|
+
if !args[:cpc] && @campaign.args[:cpc]
|
49
|
+
args[:cpc] = @campaign.args[:cpc]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
@args = args
|
54
|
+
|
34
55
|
@adgroup_data = nil
|
35
|
-
#set adgroup owner campaign
|
36
|
-
@campaign = campaign
|
37
56
|
|
38
57
|
#initialize adgroups
|
39
58
|
@adtexts = []
|
40
59
|
if args[:ads] && args[:ads].size > 0
|
41
60
|
args[:ads].each do |adtext|
|
42
|
-
@adtexts << SklikApi::Adtext.new(self
|
61
|
+
@adtexts << SklikApi::Adtext.new(adtext.merge(:adgroup => self))
|
43
62
|
end
|
44
63
|
end
|
64
|
+
|
45
65
|
#initialize adgroups
|
46
66
|
@keywords = []
|
47
67
|
if args[:keywords] && args[:keywords].size > 0
|
48
68
|
args[:keywords].each do |keyword|
|
49
|
-
|
69
|
+
if keyword.is_a?(Hash)
|
70
|
+
@keywords << SklikApi::Keyword.new(keyword.merge(:adgroup => self))
|
71
|
+
else
|
72
|
+
@keywords << SklikApi::Keyword.new(:keyword => keyword, :adgroup => self)
|
73
|
+
end
|
50
74
|
end
|
51
75
|
end
|
52
76
|
|
53
77
|
super args
|
54
78
|
end
|
55
79
|
|
56
|
-
def self.
|
80
|
+
def self.get id
|
81
|
+
if adgroup = super(NAME, id)
|
82
|
+
SklikApi::Adgroup.new(
|
83
|
+
process_sklik_data adgroup
|
84
|
+
)
|
85
|
+
else
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
#
|
90
|
+
# Find adgroups in campaign!
|
91
|
+
# !Deprecated! by campaign and args
|
92
|
+
#
|
93
|
+
def self.find args, deprecated_args = {}
|
57
94
|
out = []
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
95
|
+
#asking fo adgroup by ID
|
96
|
+
if args.is_a?(Integer)
|
97
|
+
return get args
|
98
|
+
|
99
|
+
#asking for adgroup deprecated way!
|
100
|
+
elsif args.is_a?(SklikApi::Campaign)
|
101
|
+
puts "DEPRECATION WARNING: Please update your code for SklikApi::Adgroup.find(campaign, args) to SklikApi::Adgroup.find(campaign_id: 1234) possible to add parent camapign by adding :campaign => your campaign"
|
102
|
+
campaign_id = args.args[:campaign_id]
|
103
|
+
args = deprecated_args
|
104
|
+
|
105
|
+
#asking for adgroup by hash with adgroup_id
|
106
|
+
elsif args.is_a?(Hash) && args[:adgroup_id]
|
107
|
+
if adgroup = get(args[:adgroup_id])
|
108
|
+
return [adgroup]
|
109
|
+
else
|
110
|
+
return []
|
111
|
+
end
|
112
|
+
|
113
|
+
#asking for adgroup by hash
|
114
|
+
else
|
115
|
+
campaign_id = args[:campaign_id]
|
116
|
+
end
|
117
|
+
|
118
|
+
raise ArgumentError, "Please provide campaign_id in params" unless campaign_id
|
119
|
+
|
120
|
+
super(NAME, campaign_id).each do |adgroup|
|
121
|
+
|
122
|
+
if (args[:status].nil? || (args[:status] == fix_status(adgroup))) && # find by status
|
123
|
+
(args[:name].nil? || (args[:name] == adgroup[:name]))
|
124
|
+
|
125
|
+
out << SklikApi::Adgroup.new(
|
126
|
+
process_sklik_data adgroup
|
65
127
|
)
|
66
128
|
end
|
67
129
|
end
|
68
130
|
out
|
69
131
|
end
|
70
132
|
|
133
|
+
def self.process_sklik_data adgroup = {}
|
134
|
+
{
|
135
|
+
:adgroup_id => adgroup[:id],
|
136
|
+
:cpc => adgroup[:cpc].to_f/100.0,
|
137
|
+
:name => adgroup[:name],
|
138
|
+
:status => fix_status(adgroup),
|
139
|
+
:campaign_id => adgroup[:campaignId],
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
71
143
|
def self.fix_status adgroup
|
72
144
|
if adgroup[:removed] == true
|
73
145
|
return :stopped
|
146
|
+
elsif adgroup[:status] == "suspend"
|
147
|
+
return :paused
|
74
148
|
else
|
75
149
|
return :running
|
76
150
|
end
|
@@ -78,7 +152,7 @@ Example of input hash
|
|
78
152
|
|
79
153
|
def keywords_stats from, to
|
80
154
|
output = []
|
81
|
-
keywords = Keyword.find(self)
|
155
|
+
keywords = Keyword.find(adgroup_id: self.args[:adgroup_id])
|
82
156
|
keywords.in_groups_of(100, false).each do |keywords_group|
|
83
157
|
out = connection.call("keywords.stats", keywords_group.collect{|k| k.args[:keyword_id]}, from, to ) { |param|
|
84
158
|
param[:keywordStats]
|
@@ -100,45 +174,80 @@ Example of input hash
|
|
100
174
|
@adgroup_data
|
101
175
|
else
|
102
176
|
@adgroup_data = @args
|
103
|
-
|
104
|
-
|
105
|
-
@adgroup_data[:keywords] = Keyword.find(self).collect{|k| k.to_hash}
|
106
|
-
else
|
107
|
-
@adgroup_data[:ads] = []
|
108
|
-
@adgroup_data[:keywords] = []
|
109
|
-
end
|
177
|
+
@adgroup_data[:ads] = self.adtexts.collect{|a| a.to_hash}
|
178
|
+
@adgroup_data[:keywords] = self.keywords.collect{|k| k.to_hash}
|
110
179
|
@adgroup_data
|
111
180
|
end
|
112
181
|
end
|
113
182
|
|
114
183
|
|
115
184
|
def create_args
|
116
|
-
raise ArgumentError, "Adgroup need's to know campaign_id" unless
|
117
|
-
raise ArgumentError, "Adgroup need's to know campaigns CPC" unless
|
185
|
+
raise ArgumentError, "Adgroup need's to know campaign_id" unless args[:campaign_id]
|
186
|
+
raise ArgumentError, "Adgroup need's to know campaigns CPC" unless args[:cpc]
|
118
187
|
|
119
188
|
out = []
|
120
189
|
#add campaign id to know where to create adgroup
|
121
|
-
out << @campaign.args[:campaign_id]
|
190
|
+
out << @args[:campaign_id] || @campaign.args[:campaign_id]
|
122
191
|
|
123
192
|
#add adgroup struct
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
193
|
+
c_args = {}
|
194
|
+
c_args[:name] = @args[:name]
|
195
|
+
if @args[:cpc]
|
196
|
+
c_args[:cpc] = (@args[:cpc] * 100).to_i
|
197
|
+
elsif @campaign && @campaign.args[:cpc]
|
198
|
+
c_args[:cpc] = (@campaign.args[:cpc] * 100).to_i
|
199
|
+
else
|
200
|
+
raise ArgumentError, "Please provide adgroup or parent campaign with :cpc parameter in CZK"
|
201
|
+
end
|
202
|
+
c_args[:status] = status_for_update if status_for_update
|
203
|
+
out << c_args
|
128
204
|
|
129
205
|
#return output
|
130
206
|
out
|
131
207
|
end
|
132
208
|
|
209
|
+
def update_args
|
210
|
+
out = []
|
211
|
+
|
212
|
+
#add campaign id on which will be performed update
|
213
|
+
out << @args[:adgroup_id]
|
214
|
+
|
215
|
+
#prepare campaign struct
|
216
|
+
u_args = {}
|
217
|
+
u_args[:name] = @args[:name] if @args[:name]
|
218
|
+
u_args[:status] = status_for_update if status_for_update
|
219
|
+
if @args[:cpc]
|
220
|
+
u_args[:cpc] = (@args[:cpc] * 100).to_i
|
221
|
+
elsif @campaign && @campaign.args[:cpc]
|
222
|
+
u_args[:cpc] = (@campaign.args[:cpc] * 100).to_i
|
223
|
+
end
|
224
|
+
out << u_args
|
225
|
+
|
226
|
+
out
|
227
|
+
end
|
228
|
+
|
133
229
|
def adtexts
|
134
|
-
|
230
|
+
if @args[:adgroup_id] && get_current_status == :stopped
|
231
|
+
SklikApi.log :error, "Adgroup: #{@args[:adgroup_id]} - Can't get adtexts for stopped Adgroup!"
|
232
|
+
[]
|
233
|
+
else
|
234
|
+
Adtext.find(adgroup_id: self.args[:adgroup_id])
|
235
|
+
end
|
135
236
|
end
|
136
237
|
|
137
238
|
def keywords
|
138
|
-
|
239
|
+
if @args[:adgroup_id] && get_current_status == :stopped
|
240
|
+
SklikApi.log :error, "Adgroup: #{@args[:adgroup_id]} - Can't get keywords for stopped Adgroup!"
|
241
|
+
[]
|
242
|
+
else
|
243
|
+
Keyword.find(adgroup_id: self.args[:adgroup_id])
|
244
|
+
end
|
139
245
|
end
|
140
246
|
|
141
247
|
def update args = {}
|
248
|
+
|
249
|
+
@args.merge!(args)
|
250
|
+
|
142
251
|
if args.is_a?(SklikApi::Adgroup)
|
143
252
|
#get data from another adgroup
|
144
253
|
@adtexts = args.instance_variable_get("@adtexts")
|
@@ -152,7 +261,7 @@ Example of input hash
|
|
152
261
|
@adtexts = []
|
153
262
|
if args[:ads] && args[:ads].size > 0
|
154
263
|
args[:ads].each do |adtext|
|
155
|
-
@adtexts << SklikApi::Adtext.new(self
|
264
|
+
@adtexts << SklikApi::Adtext.new(adtext.merge(:adgroup => self))
|
156
265
|
end
|
157
266
|
end
|
158
267
|
|
@@ -160,7 +269,7 @@ Example of input hash
|
|
160
269
|
@keywords = []
|
161
270
|
if args[:keywords] && args[:keywords].size > 0
|
162
271
|
args[:keywords].each do |keyword|
|
163
|
-
@keywords << SklikApi::Keyword.new(
|
272
|
+
@keywords << SklikApi::Keyword.new(:keyword => keyword, :adgroup => self)
|
164
273
|
end
|
165
274
|
end
|
166
275
|
end
|
@@ -168,83 +277,124 @@ Example of input hash
|
|
168
277
|
save
|
169
278
|
end
|
170
279
|
|
280
|
+
def valid?
|
281
|
+
clear_errors
|
282
|
+
log_error "name is required" unless args[:name] && args[:name].size > 0
|
283
|
+
log_error "cpc is required and must be higher than 0 CZK" unless !@args[:adgroup_id] && args[:cpc] && args[:cpc] > 0
|
284
|
+
log_error "campaign_id is required" unless args[:campaign_id] || (@campaign && @campaign.args[:campaign_id])
|
285
|
+
!errors.any?
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
def self.get_current_status args = {}
|
290
|
+
raise ArgumentError, "Adgroup_id is required" unless args[:adgroup_id]
|
291
|
+
if adgroup = self.get(args[:adgroup_id])
|
292
|
+
adgroup.args[:status]
|
293
|
+
else
|
294
|
+
raise ArgumentError, "Adgroup by #{args.inspect} couldn't be found!"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def get_current_status
|
299
|
+
self.class.get_current_status :adgroup_id => @args[:adgroup_id], :customer_id => @customer_id
|
300
|
+
end
|
301
|
+
|
171
302
|
def save
|
172
|
-
|
303
|
+
clear_errors
|
304
|
+
@args[:campaign_id] = @campaign.args[:campaign_id] if !@args[:campaign_id] && @campaign.args[:campaign_id]
|
173
305
|
|
174
|
-
|
175
|
-
## KEYWORDS
|
176
|
-
############
|
306
|
+
if @args[:adgroup_id] #do update
|
177
307
|
|
178
|
-
#
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
308
|
+
#get current status of campaign
|
309
|
+
before_status = get_current_status
|
310
|
+
|
311
|
+
#restore campaign before update
|
312
|
+
restore if before_status == :stopped
|
313
|
+
|
314
|
+
#rescue from any error to ensure remove will be done when something went wrong
|
315
|
+
error = nil
|
316
|
+
|
317
|
+
begin
|
318
|
+
#update adgroup
|
319
|
+
update_object
|
320
|
+
|
321
|
+
############
|
322
|
+
## KEYWORDS
|
323
|
+
############
|
324
|
+
|
325
|
+
#update keywords
|
326
|
+
keywords_error = []
|
327
|
+
@new_keywords = @keywords.clone
|
328
|
+
delete_first = true
|
329
|
+
while @new_keywords && @new_keywords.size > 0 do
|
330
|
+
begin
|
331
|
+
connection.call('keywords.set', @args[:adgroup_id], @new_keywords[0..199].collect{|k| k.create_args.last }, delete_first) do |params|
|
332
|
+
log_error params[:statusMessage] if params[:statusMessage] != "OK"
|
333
|
+
end
|
334
|
+
rescue Exception => e
|
335
|
+
log_error e.message
|
186
336
|
end
|
187
|
-
|
188
|
-
|
337
|
+
@new_keywords = @new_keywords[200..-1]
|
338
|
+
delete_first = false
|
189
339
|
end
|
190
|
-
@new_keywords = @new_keywords[200..-1]
|
191
|
-
delete_first = false
|
192
|
-
end
|
193
340
|
|
194
|
-
|
195
|
-
|
196
|
-
|
341
|
+
############
|
342
|
+
## ADTEXTS
|
343
|
+
############
|
197
344
|
|
198
|
-
|
199
|
-
|
200
|
-
|
345
|
+
#create new adtexts and delete old
|
346
|
+
@saved_adtexts = adtexts.inject({}){|o,a| o[a.uniq_identifier] = a ; o}
|
347
|
+
@new_adtexts = @adtexts.inject({}){|o,a| o[a.uniq_identifier] = a ; o}
|
201
348
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
349
|
+
#adtexts to be deleted
|
350
|
+
(@saved_adtexts.keys - @new_adtexts.keys).each do |k|
|
351
|
+
puts "deleting adtext #{@saved_adtexts[k]} in #{@args[:name]}"
|
352
|
+
#don't try to remove already removed adtext
|
353
|
+
@saved_adtexts[k].remove unless @saved_adtexts[k].args[:status] == :stopped
|
354
|
+
end
|
208
355
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
356
|
+
#adtexts to be created
|
357
|
+
(@new_adtexts.keys - @saved_adtexts.keys).each do |k|
|
358
|
+
puts "creating new adtext #{k} in #{@args[:name]}"
|
359
|
+
begin
|
360
|
+
@new_adtexts[k].save
|
361
|
+
rescue Exception => e
|
362
|
+
#take care about error message -> do it nicer
|
363
|
+
if /There is error from sklik ad.create: Invalid parameters/ =~ e.message
|
364
|
+
log_error "Problem with creating #{@new_adtexts[k].args} in adgroup #{@args[:name]}"
|
365
|
+
else
|
366
|
+
log_error e.message
|
367
|
+
end
|
220
368
|
end
|
221
369
|
end
|
222
|
-
end
|
223
370
|
|
224
|
-
|
225
|
-
|
226
|
-
|
371
|
+
#check status to be running
|
372
|
+
(@new_adtexts.keys & @saved_adtexts.keys).each do |k|
|
373
|
+
@saved_adtexts[k].restore if @saved_adtexts[k].args[:status] == :stopped
|
374
|
+
end
|
375
|
+
|
376
|
+
rescue Exception => e
|
377
|
+
log_error e.message
|
227
378
|
end
|
228
379
|
|
380
|
+
#remove it if new status is stopped or status doesn't changed and before it was stopped
|
381
|
+
remove if (@args[:status] == :stopped) || (@args[:status].nil? && before_status == :stopped)
|
229
382
|
|
230
|
-
else
|
231
|
-
#create adgroup
|
232
|
-
create
|
383
|
+
else #do create
|
233
384
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
@campaign.errors << "Problem with creating #{adtext.args} in adgroup #{@args[:name]}"
|
242
|
-
else
|
243
|
-
@campaign.errors << e.message
|
244
|
-
end
|
245
|
-
end
|
385
|
+
begin
|
386
|
+
#create adgroup
|
387
|
+
create
|
388
|
+
rescue Exception => e
|
389
|
+
log_error e.message
|
390
|
+
#don't continue with creating campaign!
|
391
|
+
return false
|
246
392
|
end
|
247
393
|
|
394
|
+
#create adtexts
|
395
|
+
unless @adtexts.all?{|adtext| adtext.save }
|
396
|
+
return rollback!
|
397
|
+
end
|
248
398
|
|
249
399
|
#create keywords
|
250
400
|
keywords_error = []
|
@@ -253,22 +403,49 @@ Example of input hash
|
|
253
403
|
while @new_keywords && @new_keywords.size > 0 do
|
254
404
|
begin
|
255
405
|
connection.call('keywords.set', @args[:adgroup_id], @new_keywords[0..199].collect{|k| k.create_args.last }, delete_first) do |params|
|
256
|
-
|
406
|
+
keywords_error << params[:statusMessage] if params[:statusMessage] != "OK"
|
257
407
|
end
|
258
408
|
rescue Exception => e
|
259
|
-
|
409
|
+
keywords_error << e.message
|
260
410
|
end
|
261
411
|
@new_keywords = @new_keywords[200..-1]
|
262
412
|
delete_first = false
|
263
413
|
end
|
264
414
|
|
265
415
|
if keywords_error.size > 0
|
266
|
-
|
416
|
+
log_error "Problem with creating keywords: #{keywords_error.join(", ")}"
|
417
|
+
return rollback!
|
267
418
|
end
|
268
419
|
|
420
|
+
#remove campaign when it was started with stopped status!
|
421
|
+
remove if @args[:status] && @args[:status].to_s.to_sym == :stopped
|
422
|
+
|
269
423
|
end
|
424
|
+
!errors.any?
|
425
|
+
end
|
426
|
+
|
427
|
+
def log_error message
|
428
|
+
@campaign.log_error "Adgroup: #{@args[:name]} -> #{message}" if @campaign
|
429
|
+
errors << message
|
270
430
|
end
|
271
431
|
|
432
|
+
def rollback!
|
433
|
+
#don't rollback if it is disabled!
|
434
|
+
return false unless SklikApi.use_rollback?
|
435
|
+
|
436
|
+
#remember errors!
|
437
|
+
old_errors = errors
|
438
|
+
|
439
|
+
SklikApi.log :info, "Adgroup: #{@args[:adgroup_id]} - ROLLBACK!"
|
440
|
+
update :name => "#{@args[:name]} FAILED ON CREATION - #{Time.now.strftime("%Y.%m.%d %H:%M:%S")}"
|
441
|
+
#remove adgroup
|
442
|
+
remove
|
443
|
+
|
444
|
+
#return remembered errors!
|
445
|
+
@errors = old_errors
|
446
|
+
#don't continue with creating adgroup!
|
447
|
+
return false
|
448
|
+
end
|
272
449
|
end
|
273
450
|
end
|
274
451
|
|