sklik-api 0.0.16 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|