three-sixty 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/README.md +95 -0
- data/lib/three-sixty/account.rb +90 -0
- data/lib/three-sixty/campaign.rb +14 -0
- data/lib/three-sixty/client.rb +105 -0
- data/lib/three-sixty/configuration.rb +21 -0
- data/lib/three-sixty/core/account.rb +43 -0
- data/lib/three-sixty/core/campaign.rb +27 -0
- data/lib/three-sixty/core/creative.rb +40 -0
- data/lib/three-sixty/core/group.rb +32 -0
- data/lib/three-sixty/core/keyword.rb +40 -0
- data/lib/three-sixty/core/report.rb +49 -0
- data/lib/three-sixty/creative.rb +27 -0
- data/lib/three-sixty/group.rb +17 -0
- data/lib/three-sixty/keyword.rb +27 -0
- data/lib/three-sixty/level.rb +9 -0
- data/lib/three-sixty/report.rb +7 -0
- data/lib/three-sixty/version.rb +3 -0
- data/lib/three-sixty.rb +13 -0
- data/three-sixty.gemspec +17 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3357b6f308efd6f848d6c5cee39547780b32dc2b
|
4
|
+
data.tar.gz: 3ad95ad642210362e42b440278ec98d7d9f8b75f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 97e80e12364c3a079c33c5f6e07abf23d2056eeacf6b60490d8341f5f339c825880779a42950024d4acc974e73aa4b90944cc9e3c18e3d0a15df1480afa8f670
|
7
|
+
data.tar.gz: 9385af23b6f6187947b989fc1e0d2feed8b99b678cf629b8f21416b3468ff08699439fa3c6c93e6d73caf408fada0c5e54d3718d9734fb257cc513d081bd8f5e
|
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# 360
|
2
|
+
A Ruby gem for connecting to the 360 Dianjing AD system, using the Open API Platform
|
3
|
+
|
4
|
+
## Install
|
5
|
+
|
6
|
+
gem 'three-sixty', github: 'forward3d/three-sixty'
|
7
|
+
|
8
|
+
|
9
|
+
## Configuration
|
10
|
+
|
11
|
+
require 'three-sixty'
|
12
|
+
ThreeSixty.configure(logger: Logger.new($stdout))
|
13
|
+
|
14
|
+
|
15
|
+
## Authenticate
|
16
|
+
|
17
|
+
require 'three-sixty'
|
18
|
+
|
19
|
+
client = ThreeSixty::Client.new(api_key, api_secret)
|
20
|
+
client.authenticate!(username, password)
|
21
|
+
|
22
|
+
You can specify a hash of optional parameters when initializing the client. These include
|
23
|
+
|
24
|
+
:endpoint - The 360 api endpoint (This is unlikely to change)
|
25
|
+
:version - The 360 api version number
|
26
|
+
:format - The api reponse format (Currently JSON or XML and is only useful when using the core library)
|
27
|
+
:logger - The client logger
|
28
|
+
|
29
|
+
|
30
|
+
## Get Campaign Ids
|
31
|
+
|
32
|
+
require 'three-sixty'
|
33
|
+
|
34
|
+
client = ThreeSixty::Client.new(api_key, api_secret)
|
35
|
+
client.authenticate!(username, password)
|
36
|
+
|
37
|
+
account = ThreeSixty::Account.new(client, opts)
|
38
|
+
campaign_ids = account.download_campaign_ids
|
39
|
+
|
40
|
+
You can specify a hash of optional parameters when initializing the account. These include
|
41
|
+
|
42
|
+
:logger - Attach a local logger
|
43
|
+
:report_generating_backoff - Create a lambda for your backoff strategy when polling the report generate e.g. lambda { |retry_number| [1 30 60 300].index(retry_number) }
|
44
|
+
|
45
|
+
## Streaming Campaign Ids to a File
|
46
|
+
|
47
|
+
File.open('campaign_ids.csv', 'w') do |file|
|
48
|
+
account.download_campaigns(campaign_ids) do |content|
|
49
|
+
file.write content
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
## Download Campaign Ids to a File
|
54
|
+
|
55
|
+
file = account.download_campaigns_to_file(campaign_ids, opts)
|
56
|
+
|
57
|
+
You can specify a hash of optional parameters, which includes
|
58
|
+
|
59
|
+
:download_dir - The directory to download the file
|
60
|
+
:filename - The full path of the file you wish to create
|
61
|
+
:encoding - The encoding used when downloading the file
|
62
|
+
|
63
|
+
## Download Campaign Info
|
64
|
+
|
65
|
+
campaign = ThreeSixty::Campaign.new(client)
|
66
|
+
campaign_info = campaign.download_all_campaigns
|
67
|
+
|
68
|
+
|
69
|
+
## Download All Ad Groups for a Campaign
|
70
|
+
|
71
|
+
group = ThreeSixty::Group.new(client)
|
72
|
+
group_info = group.download_campaign_all_ad_groups(campaigns_id)
|
73
|
+
|
74
|
+
## Download All Creatives for a Campaign
|
75
|
+
|
76
|
+
group = ThreeSixty::Group.new(client)
|
77
|
+
ad_group_ids = group.download_campaign_ad_group_ids(campaign_id)
|
78
|
+
|
79
|
+
creatives = []
|
80
|
+
creative = ThreeSixty::Creative.new(client)
|
81
|
+
ad_group_ids.each do |ad_group_id|
|
82
|
+
creatives += creative.download_ad_group_all_creatives(ad_group_id)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
## Downlod All Keywords for a Campaign
|
87
|
+
|
88
|
+
group = ThreeSixty::Group.new(client)
|
89
|
+
ad_group_ids = group.download_campaign_ad_group_ids(campaign_id)
|
90
|
+
|
91
|
+
keywords = []
|
92
|
+
keyword = ThreeSixty::Keyword.new(client)
|
93
|
+
ad_group_ids.each do |ad_group_id|
|
94
|
+
keywords += keyword.download_ad_group_all_keywords(ad_group_id)
|
95
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
require_relative 'core/account'
|
5
|
+
|
6
|
+
module ThreeSixty
|
7
|
+
class Account < ThreeSixty::Core::Account
|
8
|
+
|
9
|
+
attr_reader :report_generating_backoff, :logger
|
10
|
+
|
11
|
+
def initialize(client, opts = {})
|
12
|
+
opts = default_options.update(opts)
|
13
|
+
|
14
|
+
@report_generating_backoff = opts[:report_generating_backoff]
|
15
|
+
@logger = opts[:logger] || client.logger
|
16
|
+
|
17
|
+
super(client)
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_campaign_ids
|
21
|
+
get_campaign_id_list["campaignIdList"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def download_campaigns(campaign_ids)
|
25
|
+
file_id = get_all_objects(campaign_ids)['fileId']
|
26
|
+
|
27
|
+
retry_number = 0
|
28
|
+
file_state = get_file_state(file_id)
|
29
|
+
while report_generating?(file_state["isGenerated"])
|
30
|
+
begin
|
31
|
+
@logger.debug "Waiting for report #{file_id} on retry number #{retry_number}"
|
32
|
+
sleep report_generating_backoff.call(retry_number)
|
33
|
+
retry_number += 1
|
34
|
+
file_state = get_file_state(file_id)
|
35
|
+
rescue TypeError => e
|
36
|
+
e.message = "Waiting too long to generate the report #{file_id}" # Re-raise with a better error message
|
37
|
+
raise e
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
@logger.info "Found file #{file_state["filePath"]} with size #{"%.2f" % (file_state["fileSize"] / 2**20)} MB"
|
42
|
+
download_filestream(file_state["filePath"]) { |chunk| yield chunk }
|
43
|
+
@logger.info "Finished downloading file #{file_state["filePath"]}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def download_campaigns_to_file(campaign_ids, opts = {})
|
47
|
+
download_dir = opts[:download_dir] || "/tmp"
|
48
|
+
file = opts[:filename] || File.join(download_dir, "306_campaigns_" << SecureRandom.uuid << ".csv")
|
49
|
+
|
50
|
+
filemode = opts[:encoding].nil? ? 'w' : "w:#{opts[:encoding]}"
|
51
|
+
|
52
|
+
@logger.debug "Creating file #{file} with filemode #{filemode}"
|
53
|
+
File.open(file, filemode) do |fs|
|
54
|
+
download_campaigns(campaign_ids) do |content|
|
55
|
+
fs.write content
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@logger.info "Finished downloading file to #{file}"
|
60
|
+
file
|
61
|
+
end
|
62
|
+
|
63
|
+
def exclude_ip_list
|
64
|
+
get_exclude_ip["excludeIpList"]
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def report_generating?(status)
|
71
|
+
[ 'pending', 'process'].include?(status)
|
72
|
+
end
|
73
|
+
|
74
|
+
def download_filestream(file)
|
75
|
+
uri = URI(file)
|
76
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
77
|
+
http.request_get(file) do |response|
|
78
|
+
response.read_body { |chunk| yield chunk }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def default_options
|
84
|
+
{
|
85
|
+
report_generating_backoff: lambda { |retry_number| retry_number < 5 ? 2**retry_number : nil }
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'core/campaign'
|
2
|
+
require_relative 'account'
|
3
|
+
|
4
|
+
module ThreeSixty
|
5
|
+
class Campaign < ThreeSixty::Core::Campaign
|
6
|
+
|
7
|
+
def download_all_campaigns
|
8
|
+
account = ThreeSixty::Account.new(@client)
|
9
|
+
campaign_ids = account.download_campaign_ids
|
10
|
+
get_info_by_id_list(campaign_ids)["campaignList"]
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'digest'
|
3
|
+
require 'base64'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require_relative 'core/account'
|
7
|
+
|
8
|
+
module ThreeSixty
|
9
|
+
class Client
|
10
|
+
|
11
|
+
attr_reader :api_key, :endpoint, :version, :logger
|
12
|
+
attr_reader :access_token, :session_token
|
13
|
+
|
14
|
+
def initialize(api_key, api_secret, opts = {})
|
15
|
+
opts = default_options.update(opts)
|
16
|
+
|
17
|
+
@api_key = api_key
|
18
|
+
@api_secret = api_secret
|
19
|
+
@endpoint = opts[:endpoint]
|
20
|
+
@version = opts[:version]
|
21
|
+
@format = opts[:format]
|
22
|
+
@logger = opts[:logger]
|
23
|
+
end
|
24
|
+
|
25
|
+
def authenticate!(username, password)
|
26
|
+
account = ThreeSixty::Core::Account.new(self)
|
27
|
+
tokens = account.client_login(username, generate_passwd(password))
|
28
|
+
@access_token = tokens['accessToken']
|
29
|
+
@session_token = tokens['sessionToken']
|
30
|
+
end
|
31
|
+
|
32
|
+
def request(resource_url, params = {})
|
33
|
+
params[:format] = @format
|
34
|
+
uri = URI(generate_url(resource_url, params))
|
35
|
+
@logger.debug "Resquest url #{uri.to_s}"
|
36
|
+
req = Net::HTTP::Post.new(uri, headers = generate_headers)
|
37
|
+
@logger.debug "Sending headers #{headers}"
|
38
|
+
res = Net::HTTP.start(uri.host) do |http|
|
39
|
+
http.request(req)
|
40
|
+
end
|
41
|
+
process_response(res)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def default_options
|
47
|
+
{
|
48
|
+
endpoint: ThreeSixty.configuration[:endpoint],
|
49
|
+
version: ThreeSixty.configuration[:version],
|
50
|
+
format: ThreeSixty.configuration[:format],
|
51
|
+
logger: ThreeSixty.configuration[:logger]
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def serveToken
|
56
|
+
DateTime.now.strftime("%Y%m%d%H%M%S%L")
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_response(res)
|
60
|
+
case res.content_type
|
61
|
+
when 'application/json'
|
62
|
+
process_json_response(res.body)
|
63
|
+
else
|
64
|
+
# raise "Unable to process response of type #{res.content_type}"
|
65
|
+
res.body
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def process_json_response(content)
|
70
|
+
JSON.parse(content)
|
71
|
+
end
|
72
|
+
|
73
|
+
def generate_headers
|
74
|
+
headers = { 'serveToken' => serveToken, 'apiKey' => @api_key }
|
75
|
+
headers['accessToken'] = @access_token unless @access_token.nil?
|
76
|
+
headers['sessionToken'] = @session_token unless @session_token.nil?
|
77
|
+
headers
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_passwd(password)
|
81
|
+
encrypt(password).unpack("H2"*32).join
|
82
|
+
end
|
83
|
+
|
84
|
+
def encrypt(password)
|
85
|
+
cipher = OpenSSL::Cipher::AES128.new(:CBC)
|
86
|
+
cipher.encrypt
|
87
|
+
cipher.key, cipher.iv = generate_key_and_vector(@api_secret)
|
88
|
+
cipher.update(Digest::MD5.hexdigest(password)) + cipher.final
|
89
|
+
end
|
90
|
+
|
91
|
+
def generate_key_and_vector(secret)
|
92
|
+
secret.scan(/.{16}/m).map { |s| Base64.decode64(Base64.encode64(s)) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def generate_url(resource_url, query_params = {})
|
96
|
+
endpoint = @endpoint + (resource_url.split("/")[1] == 'clientLogin' ? '/' : '/' << version) # client login doesn't contain version in the url
|
97
|
+
[endpoint, resource_url].join('/') << '?' << querystring(query_params)
|
98
|
+
end
|
99
|
+
|
100
|
+
def querystring(query_params)
|
101
|
+
query_params.map { |key, value| key.to_s << '=' << URI.escape(value.to_s) }.join('&')
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module ThreeSixty
|
4
|
+
|
5
|
+
DEFAULT_ENDPOINT = "https://api.e.360.cn"
|
6
|
+
DEFAULT_VERSION = "1.6"
|
7
|
+
DEFAULT_FORMAT = 'json'
|
8
|
+
|
9
|
+
@@configuration = {}
|
10
|
+
|
11
|
+
def self.configure(opts = {})
|
12
|
+
@@configuration[:endpoint] = opts[:endpoint] || DEFAULT_ENDPOINT
|
13
|
+
@@configuration[:version] = opts[:version] || DEFAULT_VERSION
|
14
|
+
@@configuration[:format] = opts[:format] || DEFAULT_FORMAT
|
15
|
+
@@configuration[:logger] = opts[:logger] || Logger.new(nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.configuration
|
19
|
+
@@configuration
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ThreeSixty
|
2
|
+
module Core
|
3
|
+
class Account
|
4
|
+
|
5
|
+
SERVICE_URL = 'account'
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def client_login(username, password)
|
12
|
+
@client.request(resource_url("clientLogin"), username: username, passwd: password)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_campaign_id_list
|
16
|
+
@client.request(resource_url("getCampaignIdList"))
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_info
|
20
|
+
@client.request(resource_url("getInfo"))
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_all_objects(campaign_ids)
|
24
|
+
@client.request(resource_url("getAllObjects"), idList: campaign_ids)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_file_state(file_id)
|
28
|
+
@client.request(resource_url("getFileState"), fileId: file_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_exclude_ip
|
32
|
+
@client.request(resource_url("getExcludeIp"))
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def resource_url(service)
|
38
|
+
[SERVICE_URL, service].join("/")
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ThreeSixty
|
2
|
+
module Core
|
3
|
+
class Campaign
|
4
|
+
|
5
|
+
SERVICE_URL = 'campaign'
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_info_by_id(campaign_id)
|
12
|
+
@client.request(resource_url("getInfoById"), id: campaign_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_info_by_id_list(campaign_ids)
|
16
|
+
@client.request(resource_url("getInfoByIdList"), idList: campaign_ids)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def resource_url(service)
|
22
|
+
[SERVICE_URL, service].join("/")
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ThreeSixty
|
2
|
+
module Core
|
3
|
+
class Creative
|
4
|
+
|
5
|
+
SERVICE_URL = 'creative'
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_id_list_by_group_id(ad_group_id, opts = {})
|
12
|
+
opts.merge!(groupId: ad_group_id)
|
13
|
+
@client.request(resource_url("getIdListByGroupId"), opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_info_by_id(creative_id)
|
17
|
+
@client.request(resource_url("getInfoById"), id: creative_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_info_by_id_list(creative_ids)
|
21
|
+
@client.request(resource_url("getInfoByIdList"), idList: creative_ids)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_status_by_id_list(creative_ids)
|
25
|
+
@client.request(resource_url("getStatusByIdList"), idList: creative_ids)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_changed_id_list(from_time)
|
29
|
+
@client.request(resource_url("getChangedIdList"), fromTime: from_time)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def resource_url(service)
|
35
|
+
[SERVICE_URL, service].join("/")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ThreeSixty
|
2
|
+
module Core
|
3
|
+
class Group
|
4
|
+
|
5
|
+
SERVICE_URL = 'group'
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_id_list_by_campaign_id(campaign_id, opts = {})
|
12
|
+
opts.merge!(campaignId: campaign_id)
|
13
|
+
@client.request(resource_url("getIdListByCampaignId"), opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_info_by_id(adgroup_id)
|
17
|
+
@client.request(resource_url("getInfoById"), id: adgroup_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_info_by_id_list(adgroup_ids)
|
21
|
+
@client.request(resource_url("getInfoByIdList"), idList: adgroup_ids)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def resource_url(service)
|
27
|
+
[SERVICE_URL, service].join("/")
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ThreeSixty
|
2
|
+
module Core
|
3
|
+
class Keyword
|
4
|
+
|
5
|
+
SERVICE_URL = 'keyword'
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_id_list_by_group_id(ad_group_id, opts = {})
|
12
|
+
opts.merge!(groupId: ad_group_id)
|
13
|
+
@client.request(resource_url("getIdListByGroupId"), opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_info_by_id(keyword_id)
|
17
|
+
@client.request(resource_url("getInfoById"), id: keyword_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_status_by_id_list(keyword_ids)
|
21
|
+
@client.request(resource_url("getStatusByIdList"), idList: keyword_ids)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_info_by_id_list(keyword_ids)
|
25
|
+
@client.request(resource_url("getInfoByIdList"), idList: keyword_ids)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_changed_id_list(from_time)
|
29
|
+
@client.request(resource_url("getChangedIdList"), fromTime: from_time)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def resource_url(service)
|
35
|
+
[SERVICE_URL, service].join("/")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ThreeSixty
|
2
|
+
module Core
|
3
|
+
class Report
|
4
|
+
|
5
|
+
SERVICE_URL = 'report'
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def keyword_count(start_date, level, opts = {})
|
12
|
+
opts.merge!({startDate: start_date, level: level})
|
13
|
+
@client.request(resource_url("keywordCount"), opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def keyword(start_date, level, opts = {})
|
17
|
+
opts.merge!({startDate: start_date, level: level})
|
18
|
+
@client.request(resource_url("keyword"), opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
def creative_count(start_date, level, opts = {})
|
22
|
+
opts.merge!({startDate: start_date, level: level})
|
23
|
+
@client.request(resource_url("creativeCount"), opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def creative(start_date, level, opts = {})
|
27
|
+
opts.merge!({startDate: start_date, level: level})
|
28
|
+
@client.request(resource_url("creative"), opts)
|
29
|
+
end
|
30
|
+
|
31
|
+
def region_count(start_date, level, opts = {})
|
32
|
+
opts.merge!({startDate: start_date, level: level})
|
33
|
+
@client.request(resource_url("regionCount"), opts)
|
34
|
+
end
|
35
|
+
|
36
|
+
def region(start_date, level, opts = {})
|
37
|
+
opts.merge!({startDate: start_date, level: level})
|
38
|
+
@client.request(resource_url("region"), opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def resource_url(service)
|
44
|
+
[SERVICE_URL, service].join("/")
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'core/creative'
|
2
|
+
|
3
|
+
module ThreeSixty
|
4
|
+
class Creative < ThreeSixty::Core::Creative
|
5
|
+
|
6
|
+
def download_ad_group_creative_ids(ad_group_id, opts = {})
|
7
|
+
get_id_list_by_group_id(ad_group_id, opts)["creativeIdList"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def download_ad_group_all_creatives(ad_group_id, opts = {})
|
11
|
+
creative_ids = download_ad_group_creative_ids(ad_group_id, opts = {})
|
12
|
+
return [] if creative_ids.empty?
|
13
|
+
get_info_by_id_list(creative_ids)["creativeList"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def download_ad_group_all_creative_statuses(ad_group_id, opts = {})
|
17
|
+
creative_ids = download_ad_group_creative_ids(ad_group_id, opts = {})
|
18
|
+
return [] if creative_ids.empty?
|
19
|
+
get_status_by_id_list(creative_ids)["creativeList"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def download_changed_creative_ids(from_time)
|
23
|
+
get_changed_id_list(from_time)["creativeIdList"]
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'core/group'
|
2
|
+
require_relative 'account'
|
3
|
+
|
4
|
+
module ThreeSixty
|
5
|
+
class Group < ThreeSixty::Core::Group
|
6
|
+
|
7
|
+
def download_campaign_ad_group_ids(campaign_id, opts = {})
|
8
|
+
get_id_list_by_campaign_id(campaign_id, opts)["groupIdList"]
|
9
|
+
end
|
10
|
+
|
11
|
+
def download_campaign_all_ad_groups(campaign_id, opts = {})
|
12
|
+
ad_group_ids = download_campaign_ad_group_ids(campaign_id)
|
13
|
+
get_info_by_id_list(ad_group_ids)["groupList"]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'core/keyword'
|
2
|
+
|
3
|
+
module ThreeSixty
|
4
|
+
class Keyword < ThreeSixty::Core::Keyword
|
5
|
+
|
6
|
+
def download_ad_group_keyword_ids(ad_group_id, opts = {})
|
7
|
+
get_id_list_by_group_id(ad_group_id, opts)["keywordIdList"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def download_ad_group_all_keywords(ad_group_id, opts = {})
|
11
|
+
keyword_ids = download_ad_group_keyword_ids(ad_group_id)
|
12
|
+
return [] if keyword_ids.empty?
|
13
|
+
get_info_by_id_list(keyword_ids)["keywordList"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def download_ad_group_all_keyword_statuses(ad_group_id, opts = {})
|
17
|
+
keyword_ids = download_ad_group_keyword_ids(ad_group_id)
|
18
|
+
return [] if keyword_ids.empty?
|
19
|
+
get_status_by_id_list(keyword_ids)["keywordList"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def download_changed_keyword_ids(from_time)
|
23
|
+
get_changed_id_list(from_time)["keywordIdList"]
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/three-sixty.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'three-sixty/level'
|
2
|
+
require_relative 'three-sixty/configuration'
|
3
|
+
require_relative 'three-sixty/campaign'
|
4
|
+
require_relative 'three-sixty/account'
|
5
|
+
require_relative 'three-sixty/client'
|
6
|
+
require_relative 'three-sixty/group'
|
7
|
+
require_relative 'three-sixty/creative'
|
8
|
+
require_relative 'three-sixty/keyword'
|
9
|
+
require_relative 'three-sixty/report'
|
10
|
+
|
11
|
+
module ThreeSixty
|
12
|
+
ThreeSixty.configure
|
13
|
+
end
|
data/three-sixty.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.expand_path('../lib', __FILE__), 'three-sixty', 'version')
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = "three-sixty"
|
5
|
+
gem.version = ThreeSixty::VERSION
|
6
|
+
gem.authors = ["Daniel Padden"]
|
7
|
+
gem.email = ["daniel.padden@forward3d.com"]
|
8
|
+
gem.description = %q{Connecting to the 360 api}
|
9
|
+
gem.summary = %q{Gathering data from the 360 api}
|
10
|
+
gem.homepage = ""
|
11
|
+
|
12
|
+
gem.files = `git ls-files -z`.split("\x0")
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: three-sixty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Padden
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-17 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Connecting to the 360 api
|
14
|
+
email:
|
15
|
+
- daniel.padden@forward3d.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- .gitignore
|
21
|
+
- README.md
|
22
|
+
- lib/three-sixty.rb
|
23
|
+
- lib/three-sixty/account.rb
|
24
|
+
- lib/three-sixty/campaign.rb
|
25
|
+
- lib/three-sixty/client.rb
|
26
|
+
- lib/three-sixty/configuration.rb
|
27
|
+
- lib/three-sixty/core/account.rb
|
28
|
+
- lib/three-sixty/core/campaign.rb
|
29
|
+
- lib/three-sixty/core/creative.rb
|
30
|
+
- lib/three-sixty/core/group.rb
|
31
|
+
- lib/three-sixty/core/keyword.rb
|
32
|
+
- lib/three-sixty/core/report.rb
|
33
|
+
- lib/three-sixty/creative.rb
|
34
|
+
- lib/three-sixty/group.rb
|
35
|
+
- lib/three-sixty/keyword.rb
|
36
|
+
- lib/three-sixty/level.rb
|
37
|
+
- lib/three-sixty/report.rb
|
38
|
+
- lib/three-sixty/version.rb
|
39
|
+
- three-sixty.gemspec
|
40
|
+
homepage: ''
|
41
|
+
licenses: []
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 2.2.1
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: Gathering data from the 360 api
|
63
|
+
test_files: []
|