sklik-api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,99 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class SklikApi
3
+ class Adtext
4
+
5
+ NAME = "ad"
6
+
7
+ include Object
8
+ =begin
9
+ Example of input hash
10
+ {
11
+ :headline => "Super headline",
12
+ :description1 => "Trying to do ",
13
+ :description2 => "best description ever",
14
+ :display_url => "my_test_url.cz",
15
+ :url => "http://my_test_url.cz"
16
+ }
17
+
18
+
19
+ =end
20
+
21
+ def initialize adgroup, args
22
+ @adtext_data = nil
23
+ #set adtext owner adgroup
24
+ @adgroup = adgroup
25
+
26
+ super args
27
+ end
28
+
29
+
30
+ def create_args
31
+ raise ArgumentError, "Adtexts need's to know adgroup_id" unless @adgroup.args[:adgroup_id]
32
+ out = []
33
+ #add campaign id to know where to create adgroup
34
+ out << @adgroup.args[:adgroup_id]
35
+
36
+ #add adtext struct
37
+ args = {}
38
+ args[:creative1] = @args[:headline]
39
+ args[:creative2] = @args[:description1]
40
+ args[:creative3] = @args[:description2]
41
+ args[:clickthruText] = @args[:display_url]
42
+ args[:clickthruUrl] = @args[:url]
43
+ out << args
44
+
45
+ #return output
46
+ out
47
+ end
48
+
49
+ def self.find adgroup, args = {}
50
+ out = []
51
+ super(NAME, adgroup.args[:adgroup_id]).each do |adtext|
52
+ if args[:adtext_id].nil? || (args[:adtext_id] && args[:adtext_id].to_i == adtext[:id].to_i)
53
+ out << Adtext.new(
54
+ adgroup,
55
+ :adtext_id => adtext[:id],
56
+ :headline => adtext[:creative1],
57
+ :description1 => adtext[:creative2],
58
+ :description2 => adtext[:creative3],
59
+ :display_url =>adtext[:clickthruText],
60
+ :url => adtext[:clickthruUrl],
61
+ :name => adtext[:name],
62
+ :status => fix_status(adtext)
63
+ )
64
+ end
65
+ end
66
+ out
67
+ end
68
+
69
+ def self.fix_status adtext
70
+ if adtext[:removed] == true
71
+ return :stopped
72
+ elsif adtext[:status] == "active"
73
+ return :running
74
+ elsif adtext[:status] == "suspend"
75
+ return :paused
76
+ else
77
+ return :unknown
78
+ end
79
+ end
80
+
81
+ def to_hash
82
+ if @adtext_data
83
+ @adtext_data
84
+ else
85
+ @adtext_data = @args
86
+ end
87
+ end
88
+
89
+ def save
90
+ if @args[:adtext_id] #do update
91
+
92
+ else #do save
93
+ #create adtext
94
+ create
95
+ end
96
+ end
97
+ end
98
+ end
99
+
@@ -0,0 +1,109 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class SklikApi
3
+ class Keyword
4
+
5
+ NAME = "keyword"
6
+
7
+ include Object
8
+ =begin
9
+ Example of input hash
10
+ {
11
+ :keyword => "\"some funny keyword\""
12
+ }
13
+ =end
14
+
15
+ def initialize adgroup, args
16
+ @keyword_data = nil
17
+ #set keyword owner adgroup
18
+ @adgroup = adgroup
19
+
20
+ super args
21
+ end
22
+
23
+ def create_args
24
+ raise ArgumentError, "Keyword need's to know adgroup_id" unless @adgroup.args[:adgroup_id]
25
+ out = []
26
+ #add campaign id to know where to create adgroup
27
+ out << @adgroup.args[:adgroup_id]
28
+
29
+ #add adtext struct
30
+ args = {}
31
+ args[:name] = strip_match_type @args[:keyword]
32
+ args[:matchType] = get_math_type @args[:keyword]
33
+ out << args
34
+
35
+ #return output
36
+ out
37
+ end
38
+
39
+ def strip_match_type keyword
40
+ keyword.gsub(/(\[|\]|\")/, "")
41
+ end
42
+
43
+ def get_math_type keyword
44
+ if /^\[.*\]$/ =~ keyword
45
+ return "exact"
46
+ elsif /^\".*\"$/ =~ keyword
47
+ return "phrase"
48
+ else
49
+ return "broad"
50
+ end
51
+ end
52
+
53
+ def self.apply_math_type keyword, match_type
54
+ return case match_type
55
+ when "broad" then keyword
56
+ when "phrase" then "\"#{keyword}\""
57
+ when "exact" then "[#{keyword}]"
58
+ else keyword
59
+ end
60
+ end
61
+
62
+ def self.find adgroup, args = {}
63
+ out = []
64
+ super(NAME, adgroup.args[:adgroup_id]).each do |keyword|
65
+ if args[:keyword_id].nil? || (args[:keyword_id] && args[:keyword_id].to_i == keyword[:id].to_i)
66
+ out << Keyword.new(
67
+ adgroup,
68
+ :keyword_id => keyword[:id],
69
+ :keyword => apply_math_type(keyword[:name], keyword[:matchType] ),
70
+ :status => fix_status(keyword)
71
+ )
72
+ end
73
+ end
74
+ out
75
+ end
76
+
77
+ def self.fix_status keyword
78
+ if keyword[:removed] == true
79
+ return :stopped
80
+ elsif keyword[:status] == "active"
81
+ return :running
82
+ elsif keyword[:status] == "suspend"
83
+ return :paused
84
+ elsif keyword[:status] == "nonactive"
85
+ return :paused_by_low_cpc
86
+ else
87
+ return :unknown
88
+ end
89
+ end
90
+
91
+ def to_hash
92
+ if @keyword_data
93
+ @keyword_data
94
+ else
95
+ @keyword_data = @args[:keyword]
96
+ end
97
+ end
98
+
99
+ def save
100
+ if @args[:keyword_id] #do update
101
+
102
+ else #do save
103
+ #create adtext
104
+ create
105
+ end
106
+ end
107
+ end
108
+ end
109
+
@@ -0,0 +1,82 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class SklikApi
3
+ class Connection
4
+
5
+ MAX_RETRIES = 3
6
+ DEFAULTS = {
7
+ :debug => false,
8
+ :timeout => 100
9
+ }
10
+
11
+ def initialize args = {}
12
+ @args = DEFAULTS.merge(args)
13
+ end
14
+
15
+ def self.connection
16
+ @connection ||= SklikApi::Connection.new(:debug => false)
17
+ end
18
+
19
+ #prepare connection to sklik
20
+ def connection
21
+ server = XMLRPC::Client.new3(:host => "api.sklik.cz", :path => "/RPC2", :port => 443, :use_ssl => true, :timeout => @args[:timeout])
22
+ server.instance_variable_get(:@http).instance_variable_set(:@verify_mode, OpenSSL::SSL::VERIFY_NONE)
23
+ #fix of UTF-8 encoding
24
+ server.extend(XMLRPCWorkAround)
25
+ #debug mode to see what XMLRPC is doing
26
+ server.set_debug(File.open("log/xmlrpc-#{Time.now.strftime("%Y_%m_%d-%H_%M_%S")}.log","a:UTF-8")) if @args[:debug]
27
+
28
+ server
29
+ end
30
+
31
+ #Get session is method for login into sklik
32
+ #save session for other requests until it expires
33
+ #every taxonomy has its own session!
34
+ def get_session force = false
35
+ @session ||= {}
36
+ if @session.has_key?(SklikApi::Access.uniq_identifier) && !force
37
+ @session[SklikApi::Access.uniq_identifier]
38
+ else
39
+ begin
40
+ param = connection.call("client.login", SklikApi::Access.email, SklikApi::Access.password).symbolize_keys
41
+ if param[:status] == 401
42
+ raise ArgumentError, "Invalid login for: #{SklikApi::Access.email}"
43
+ elsif param[:status] == 200
44
+ return @session[SklikApi::Access.uniq_identifier] = param[:session]
45
+ else
46
+ raise ArgumentError, param[:statusMessage]
47
+ end
48
+ rescue XMLRPC::FaultException => e
49
+ raise ArgumentError, "#{e.faultString}, #{e.faultCode}"
50
+ rescue Exception => e
51
+ raise e
52
+ end
53
+ end
54
+ end
55
+
56
+ # method to wrap method call to sklik -> allow retry and problem with session expiration
57
+ def call method, *args
58
+ retry_count = MAX_RETRIES
59
+ begin
60
+ #get response from sklik
61
+ param = connection.call( method, get_session, *args ).symbolize_keys
62
+ if param[:status] == 200
63
+ return yield(param)
64
+ elsif param[:status] == 406
65
+ raise ArgumentError, "Sklik returned: #{param[:statusMessage]} \n #{args.inspect}"
66
+ elsif param[:statusMessage] == "Session has expired or is malformed."
67
+ raise ArgumentError, "session has expired"
68
+ else
69
+ raise ArgumentError, "There is error from sklik #{method}: #{param[:statusMessage]}"
70
+ end
71
+ rescue Exception => e
72
+ pp "Rescuing from request by: #{e.class} - #{e.message}"
73
+ #if session expired then get new one! and retry
74
+ get_session(true) if e.message == "session has expired"
75
+
76
+ retry_count -= 1
77
+ retry if retry_count > 0
78
+ raise e
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,60 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class SklikApi
3
+ module Object
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def connection
12
+ SklikApi::Connection.connection
13
+ end
14
+
15
+ def find name, id = nil
16
+ if id
17
+ args = ["list#{name.pluralize.camelize}", id]
18
+ else
19
+ args = ["list#{name.pluralize.camelize}"]
20
+ end
21
+ return connection.call(*args) { |param|
22
+ #return list of all objects
23
+ param[name.pluralize.to_sym].collect{|c| c.symbolize_keys }
24
+ }
25
+ end
26
+ end
27
+
28
+ module InstanceMethods
29
+ #get connection for request
30
+ def connection
31
+ SklikApi::Connection.connection
32
+ end
33
+
34
+ def initialize args
35
+ @args = args
36
+ return self
37
+ end
38
+
39
+ def args
40
+ @args
41
+ end
42
+
43
+ def create
44
+ out = connection.call("#{self.class::NAME}.create", *create_args ) { |param|
45
+ param["#{self.class::NAME}Id".to_sym]
46
+ }
47
+ @args["#{self.class.to_s.downcase.split(":").last}_id".to_sym] = out
48
+ @args
49
+ end
50
+
51
+ def create_args
52
+ raise(NoMethodError, "Please implement 'create_args' method in class: #{self.class} - should return array which will be placed into create method")
53
+ end
54
+
55
+ def to_hash
56
+ raise(NoMethodError, "Please implement 'to_hash' method in class: #{self.class} - should return hash which contains all data")
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ #Settings for sklik & eTarget
4
+ XMLRPC::Config.const_set(:ENABLE_NIL_PARSER, true)
5
+ XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, true)
6
+
7
+ #Hack for enabling debug mode!
8
+ class XMLRPC::Client
9
+ def set_debug out = $stderr
10
+ @http.set_debug_output(out);
11
+ end
12
+ end
13
+
14
+ #Hack for force encoding to UTF-8
15
+ module XMLRPCWorkAround
16
+ def do_rpc(request, async=false)
17
+ data = super
18
+ data.force_encoding("UTF-8")
19
+ data
20
+ end
21
+ end
@@ -0,0 +1,101 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "sklik-api"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ondrej Bartas"]
12
+ s.date = "2012-03-25"
13
+ s.description = "Sklik advertising PPC api for creating campaigns and updating them when they runs"
14
+ s.email = "ondrej@bartas.cz"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "LICENSE.txt",
23
+ "README.markdown",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "config/access.rb.example",
27
+ "lib/sklik-api.rb",
28
+ "lib/sklik-api/access.rb",
29
+ "lib/sklik-api/campaign.rb",
30
+ "lib/sklik-api/campaign_parts/adgroup.rb",
31
+ "lib/sklik-api/campaign_parts/adtext.rb",
32
+ "lib/sklik-api/campaign_parts/keyword.rb",
33
+ "lib/sklik-api/connection.rb",
34
+ "lib/sklik-api/sklik_object.rb",
35
+ "lib/sklik-api/xmlrpc_setup.rb",
36
+ "sklik-api.gemspec",
37
+ "test/fake_web.rb",
38
+ "test/helper.rb",
39
+ "test/unit/campaign.rb"
40
+ ]
41
+ s.homepage = "http://github.com/ondrejbartas/sklik-api"
42
+ s.licenses = ["MIT"]
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = "1.8.10"
45
+ s.summary = "Sklik advertising PPC api for creating campaigns"
46
+
47
+ if s.respond_to? :specification_version then
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<json>, [">= 0"])
52
+ s.add_runtime_dependency(%q<unicode>, ["~> 0.4.0"])
53
+ s.add_runtime_dependency(%q<text>, ["~> 0.2.0"])
54
+ s.add_runtime_dependency(%q<i18n>, ["~> 0.6.0"])
55
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3.1.0"])
56
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
57
+ s.add_development_dependency(%q<shoulda-context>, [">= 0"])
58
+ s.add_development_dependency(%q<turn>, ["~> 0.8.2"])
59
+ s.add_development_dependency(%q<minitest>, [">= 0"])
60
+ s.add_development_dependency(%q<ansi>, ["~> 1.2.5"])
61
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
62
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
63
+ s.add_development_dependency(%q<thin>, [">= 0"])
64
+ s.add_development_dependency(%q<shotgun>, [">= 0"])
65
+ s.add_development_dependency(%q<rcov>, ["= 0.9.10"])
66
+ else
67
+ s.add_dependency(%q<json>, [">= 0"])
68
+ s.add_dependency(%q<unicode>, ["~> 0.4.0"])
69
+ s.add_dependency(%q<text>, ["~> 0.2.0"])
70
+ s.add_dependency(%q<i18n>, ["~> 0.6.0"])
71
+ s.add_dependency(%q<activesupport>, ["~> 3.1.0"])
72
+ s.add_dependency(%q<rack-test>, [">= 0"])
73
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
74
+ s.add_dependency(%q<turn>, ["~> 0.8.2"])
75
+ s.add_dependency(%q<minitest>, [">= 0"])
76
+ s.add_dependency(%q<ansi>, ["~> 1.2.5"])
77
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
78
+ s.add_dependency(%q<fakeweb>, [">= 0"])
79
+ s.add_dependency(%q<thin>, [">= 0"])
80
+ s.add_dependency(%q<shotgun>, [">= 0"])
81
+ s.add_dependency(%q<rcov>, ["= 0.9.10"])
82
+ end
83
+ else
84
+ s.add_dependency(%q<json>, [">= 0"])
85
+ s.add_dependency(%q<unicode>, ["~> 0.4.0"])
86
+ s.add_dependency(%q<text>, ["~> 0.2.0"])
87
+ s.add_dependency(%q<i18n>, ["~> 0.6.0"])
88
+ s.add_dependency(%q<activesupport>, ["~> 3.1.0"])
89
+ s.add_dependency(%q<rack-test>, [">= 0"])
90
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
91
+ s.add_dependency(%q<turn>, ["~> 0.8.2"])
92
+ s.add_dependency(%q<minitest>, [">= 0"])
93
+ s.add_dependency(%q<ansi>, ["~> 1.2.5"])
94
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
95
+ s.add_dependency(%q<fakeweb>, [">= 0"])
96
+ s.add_dependency(%q<thin>, [">= 0"])
97
+ s.add_dependency(%q<shotgun>, [">= 0"])
98
+ s.add_dependency(%q<rcov>, ["= 0.9.10"])
99
+ end
100
+ end
101
+