three-sixty 0.0.1
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.
- 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: []
|