twitter-ads 5.2.0 → 8.0.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.
- checksums.yaml +4 -4
- data/LICENSE +1 -2
- data/README.md +1 -1
- data/lib/twitter-ads.rb +8 -4
- data/lib/twitter-ads/account.rb +6 -24
- data/lib/twitter-ads/audiences/tailored_audience.rb +56 -1
- data/lib/twitter-ads/{targeting_criteria/behavior_taxonomy.rb → campaign/advertiser_business_categories.rb} +6 -6
- data/lib/twitter-ads/campaign/campaign.rb +1 -2
- data/lib/twitter-ads/campaign/content_categories.rb +23 -0
- data/lib/twitter-ads/campaign/funding_instrument.rb +1 -2
- data/lib/twitter-ads/campaign/line_item.rb +4 -4
- data/lib/twitter-ads/campaign/organic_tweet.rb +1 -3
- data/lib/twitter-ads/campaign/targeting_criteria.rb +1 -1
- data/lib/twitter-ads/campaign/tweet.rb +4 -49
- data/lib/twitter-ads/client.rb +2 -2
- data/lib/twitter-ads/creative/account_media.rb +4 -6
- data/lib/twitter-ads/creative/draft_tweet.rb +40 -0
- data/lib/twitter-ads/creative/image_app_download_card.rb +2 -2
- data/lib/twitter-ads/creative/image_conversation_card.rb +3 -2
- data/lib/twitter-ads/creative/media_creative.rb +2 -3
- data/lib/twitter-ads/creative/media_library.rb +12 -13
- data/lib/twitter-ads/creative/promoted_account.rb +1 -2
- data/lib/twitter-ads/creative/promoted_tweet.rb +2 -3
- data/lib/twitter-ads/creative/scheduled_tweet.rb +1 -12
- data/lib/twitter-ads/creative/tweets.rb +52 -0
- data/lib/twitter-ads/creative/video_app_download_card.rb +4 -6
- data/lib/twitter-ads/creative/video_conversation_card.rb +6 -6
- data/lib/twitter-ads/creative/video_website_card.rb +3 -5
- data/lib/twitter-ads/creative/website_card.rb +2 -2
- data/lib/twitter-ads/cursor.rb +6 -0
- data/lib/twitter-ads/enum.rb +22 -13
- data/lib/twitter-ads/error.rb +5 -15
- data/lib/twitter-ads/http/request.rb +37 -2
- data/lib/twitter-ads/http/response.rb +1 -13
- data/lib/twitter-ads/resources/analytics.rb +99 -47
- data/lib/twitter-ads/resources/dsl.rb +8 -1
- data/lib/twitter-ads/restapi.rb +29 -0
- data/lib/twitter-ads/settings/tax.rb +13 -1
- data/lib/twitter-ads/targeting/audience_summary.rb +47 -0
- data/lib/twitter-ads/targeting_criteria/{behavior.rb → conversation.rb} +3 -7
- data/lib/twitter-ads/targeting_criteria/event.rb +1 -0
- data/lib/twitter-ads/utils.rb +23 -0
- data/lib/twitter-ads/version.rb +1 -1
- data/spec/fixtures/audience_summary.json +14 -0
- data/spec/fixtures/line_items_all.json +2 -10
- data/spec/fixtures/line_items_load.json +0 -1
- data/spec/fixtures/tailored_audiences_all.json +3 -0
- data/spec/fixtures/targeted_audiences.json +33 -0
- data/spec/fixtures/tweet_previews.json +23 -0
- data/spec/spec_helper.rb +1 -4
- data/spec/twitter-ads/audiences/tailored_audience_spec.rb +25 -2
- data/spec/twitter-ads/campaign/line_item_spec.rb +0 -1
- data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +1 -1
- data/spec/twitter-ads/campaign/tweet_spec.rb +0 -59
- data/spec/twitter-ads/client_spec.rb +17 -1
- data/spec/twitter-ads/creative/media_creative_spec.rb +1 -1
- data/spec/twitter-ads/creative/promoted_tweet_spec.rb +18 -0
- data/spec/twitter-ads/creative/tweet_previews_spec.rb +41 -0
- data/spec/twitter-ads/rate_limit_spec.rb +247 -0
- data/spec/twitter-ads/retry_count_spec.rb +61 -0
- data/spec/twitter-ads/{creative/image_app_download_card_spec.rb → targeting/audience_summary_spec.rb} +16 -18
- metadata +50 -49
- data/lib/twitter-ads/audiences/audience_intelligence.rb +0 -68
- data/lib/twitter-ads/targeting/reach_estimate.rb +0 -78
- data/spec/fixtures/tweet_preview.json +0 -24
- data/spec/twitter-ads/campaign/reach_estimate_spec.rb +0 -103
- data/spec/twitter-ads/creative/account_media_spec.rb +0 -32
- data/spec/twitter-ads/creative/image_conversation_card_spec.rb +0 -40
- data/spec/twitter-ads/creative/video_app_download_card_spec.rb +0 -42
- data/spec/twitter-ads/creative/video_conversation_card_spec.rb +0 -51
- data/spec/twitter-ads/creative/website_card_spec.rb +0 -42
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright (C) 2019 Twitter, Inc.
|
3
|
+
|
4
|
+
module TwitterAds
|
5
|
+
module AudienceSummary
|
6
|
+
|
7
|
+
include TwitterAds::DSL
|
8
|
+
include TwitterAds::Resource
|
9
|
+
|
10
|
+
RESOURCE = "/#{TwitterAds::API_VERSION}/" \
|
11
|
+
'accounts/%{account_id}/audience_summary'
|
12
|
+
|
13
|
+
property :audience_size, read_only: true
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
# Get an audience summary for the specified targeting criteria.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# TwitterAds::AudienceSummary.fetch(
|
21
|
+
# account,
|
22
|
+
# params: {targeting_criteria:[{targeting_type:'LOCATION',
|
23
|
+
# targeting_value:'96683cc9126741d1'}]}
|
24
|
+
# )
|
25
|
+
#
|
26
|
+
# @param params [Hash] A hash of input targeting criteria values
|
27
|
+
#
|
28
|
+
# @return [Hash] A hash containing the min and max audience size.
|
29
|
+
#
|
30
|
+
# @since 7.0.0
|
31
|
+
# @see https://developer.twitter.com/en/docs/ads/campaign-management/api-reference/audience-summary
|
32
|
+
def fetch(account, params)
|
33
|
+
resource = RESOURCE % { account_id: account.id }
|
34
|
+
headers = { 'Content-Type' => 'application/json' }
|
35
|
+
|
36
|
+
response = TwitterAds::Request.new(account.client,
|
37
|
+
:post,
|
38
|
+
resource,
|
39
|
+
headers: headers,
|
40
|
+
body: params.to_json).perform
|
41
|
+
response.body[:data]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -2,22 +2,18 @@
|
|
2
2
|
# Copyright (C) 2019 Twitter, Inc.
|
3
3
|
|
4
4
|
module TwitterAds
|
5
|
-
class
|
5
|
+
class Conversation
|
6
6
|
|
7
7
|
include TwitterAds::DSL
|
8
8
|
include TwitterAds::Resource
|
9
9
|
|
10
|
-
property :id, read_only: true
|
11
10
|
property :name, read_only: true
|
12
11
|
property :targeting_type, read_only: true
|
13
12
|
property :targeting_value, read_only: true
|
14
|
-
property :
|
15
|
-
property :country_code, read_only: true
|
16
|
-
property :partner_source, read_only: true
|
17
|
-
property :targetable_type, read_only: true
|
13
|
+
property :conversation_type, read_only: true
|
18
14
|
|
19
15
|
RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
|
20
|
-
'targeting_criteria/
|
16
|
+
'targeting_criteria/conversations' # @api private
|
21
17
|
|
22
18
|
def initialize(account)
|
23
19
|
@account = account
|
@@ -21,6 +21,7 @@ module TwitterAds
|
|
21
21
|
property :gender_breakdown_percentage, read_only: true
|
22
22
|
property :device_breakdown_percentage, read_only: true
|
23
23
|
property :country_breakdown_percentage, read_only: true
|
24
|
+
property :targeting_value, read_only: true
|
24
25
|
|
25
26
|
RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
|
26
27
|
'targeting_criteria/events' # @api private
|
data/lib/twitter-ads/utils.rb
CHANGED
@@ -70,6 +70,29 @@ module TwitterAds
|
|
70
70
|
warn message
|
71
71
|
end
|
72
72
|
|
73
|
+
def extract_response_headers(headers)
|
74
|
+
values = {}
|
75
|
+
# only get "X-${name}" custom response headers
|
76
|
+
headers.each { |key, value|
|
77
|
+
if key =~ /^x-/
|
78
|
+
values[key.gsub(/^x-/, '').tr('-', '_')] = \
|
79
|
+
value.first =~ /^[0-9]*$/ ? value.first.to_i : value.first
|
80
|
+
end
|
81
|
+
}
|
82
|
+
values
|
83
|
+
end
|
84
|
+
|
85
|
+
def flatten_params(args)
|
86
|
+
params = args
|
87
|
+
params.each { |key, value|
|
88
|
+
if value.is_a?(Array)
|
89
|
+
next if value.empty?
|
90
|
+
params[key] = value.join(',')
|
91
|
+
end
|
92
|
+
}
|
93
|
+
params
|
94
|
+
end
|
95
|
+
|
73
96
|
end
|
74
97
|
|
75
98
|
end
|
data/lib/twitter-ads/version.rb
CHANGED
@@ -29,7 +29,6 @@
|
|
29
29
|
"currency": "USD",
|
30
30
|
"created_at": "2011-07-11T20:36:11Z",
|
31
31
|
"updated_at": "2011-09-04T19:39:51Z",
|
32
|
-
"include_sentiment": null,
|
33
32
|
"campaign_id": "2wap7",
|
34
33
|
"deleted": false
|
35
34
|
},
|
@@ -57,7 +56,6 @@
|
|
57
56
|
"currency": "USD",
|
58
57
|
"created_at": "2011-07-13T20:56:39Z",
|
59
58
|
"updated_at": "2011-09-04T19:39:04Z",
|
60
|
-
"include_sentiment": null,
|
61
59
|
"campaign_id": "2wamv",
|
62
60
|
"deleted": false
|
63
61
|
},
|
@@ -85,7 +83,6 @@
|
|
85
83
|
"currency": "USD",
|
86
84
|
"created_at": "2011-07-14T00:04:47Z",
|
87
85
|
"updated_at": "2011-09-04T19:39:39Z",
|
88
|
-
"include_sentiment": null,
|
89
86
|
"campaign_id": "2wai9",
|
90
87
|
"deleted": false
|
91
88
|
},
|
@@ -113,7 +110,6 @@
|
|
113
110
|
"currency": "USD",
|
114
111
|
"created_at": "2011-08-22T22:42:18Z",
|
115
112
|
"updated_at": "2011-09-04T19:40:02Z",
|
116
|
-
"include_sentiment": null,
|
117
113
|
"campaign_id": "2of1n",
|
118
114
|
"deleted": false
|
119
115
|
},
|
@@ -141,7 +137,7 @@
|
|
141
137
|
"currency": "JPY",
|
142
138
|
"created_at": "2011-08-26T20:51:14Z",
|
143
139
|
"updated_at": "2011-08-26T21:30:25Z",
|
144
|
-
|
140
|
+
|
145
141
|
"campaign_id": "2w9n1",
|
146
142
|
"deleted": true
|
147
143
|
},
|
@@ -169,7 +165,7 @@
|
|
169
165
|
"currency": "USD",
|
170
166
|
"created_at": "2011-08-26T21:38:51Z",
|
171
167
|
"updated_at": "2011-08-26T22:24:37Z",
|
172
|
-
|
168
|
+
|
173
169
|
"campaign_id": "2vuug",
|
174
170
|
"deleted": true
|
175
171
|
},
|
@@ -197,7 +193,6 @@
|
|
197
193
|
"currency": "JPY",
|
198
194
|
"created_at": "2011-08-26T22:28:55Z",
|
199
195
|
"updated_at": "2011-09-04T19:38:46Z",
|
200
|
-
"include_sentiment": null,
|
201
196
|
"campaign_id": "2vuj3",
|
202
197
|
"deleted": false
|
203
198
|
},
|
@@ -225,7 +220,6 @@
|
|
225
220
|
"currency": "USD",
|
226
221
|
"created_at": "2011-09-01T17:25:04Z",
|
227
222
|
"updated_at": "2011-09-16T02:56:55Z",
|
228
|
-
"include_sentiment": null,
|
229
223
|
"campaign_id": "2v3c4",
|
230
224
|
"deleted": true
|
231
225
|
},
|
@@ -253,7 +247,6 @@
|
|
253
247
|
"currency": "JPY",
|
254
248
|
"created_at": "2011-09-06T17:42:52Z",
|
255
249
|
"updated_at": "2011-09-30T18:54:18Z",
|
256
|
-
"include_sentiment": null,
|
257
250
|
"campaign_id": "2ttv3",
|
258
251
|
"deleted": false
|
259
252
|
},
|
@@ -281,7 +274,6 @@
|
|
281
274
|
"currency": "USD",
|
282
275
|
"created_at": "2011-09-06T22:44:13Z",
|
283
276
|
"updated_at": "2011-09-20T01:32:27Z",
|
284
|
-
"include_sentiment": null,
|
285
277
|
"campaign_id": "2ttv3",
|
286
278
|
"deleted": true
|
287
279
|
}
|
@@ -14,6 +14,7 @@
|
|
14
14
|
],
|
15
15
|
"audience_type": "WEB",
|
16
16
|
"id": "abc2",
|
17
|
+
"owner_account_id": "18ce54uhdu0",
|
17
18
|
"reasons_not_targetable": [
|
18
19
|
"TOO_SMALL"
|
19
20
|
],
|
@@ -33,6 +34,7 @@
|
|
33
34
|
],
|
34
35
|
"audience_type": "CRM",
|
35
36
|
"id": "abc1",
|
37
|
+
"owner_account_id": "18ce54uhdu0",
|
36
38
|
"reasons_not_targetable": [],
|
37
39
|
"list_type": "DEVICE_ID",
|
38
40
|
"created_at": "2014-05-22T17:37:12Z",
|
@@ -50,6 +52,7 @@
|
|
50
52
|
],
|
51
53
|
"audience_type": "CRM",
|
52
54
|
"id": "abc3",
|
55
|
+
"owner_account_id": "18ce54uhdu0",
|
53
56
|
"reasons_not_targetable": [
|
54
57
|
"TOO_SMALL"
|
55
58
|
],
|
@@ -0,0 +1,33 @@
|
|
1
|
+
{
|
2
|
+
"request": {
|
3
|
+
"params": {
|
4
|
+
"account_id": "2iqph",
|
5
|
+
"tailored_audience_id": "abc2"
|
6
|
+
}
|
7
|
+
},
|
8
|
+
"next_cursor": null,
|
9
|
+
"data": [
|
10
|
+
{
|
11
|
+
"campaign_id": "59hod",
|
12
|
+
"campaign_name": "test-campaign",
|
13
|
+
"line_items": [
|
14
|
+
{
|
15
|
+
"id": "5gzog",
|
16
|
+
"name": "test-line-item",
|
17
|
+
"servable": true
|
18
|
+
}
|
19
|
+
]
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"campaign_id": "arja7",
|
23
|
+
"campaign_name": "Untitled campaign",
|
24
|
+
"line_items": [
|
25
|
+
{
|
26
|
+
"id": "bjw1q",
|
27
|
+
"name": null,
|
28
|
+
"servable": true
|
29
|
+
}
|
30
|
+
]
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "tweet_previews",
|
3
|
+
"request": {
|
4
|
+
"params": {
|
5
|
+
"tweet_ids": [
|
6
|
+
"1130942781109596160",
|
7
|
+
"1101254234031370240"
|
8
|
+
],
|
9
|
+
"tweet_type": "PUBLISHED",
|
10
|
+
"account_id": "2iqph"
|
11
|
+
}
|
12
|
+
},
|
13
|
+
"data": [
|
14
|
+
{
|
15
|
+
"tweet_id": "1130942781109596160",
|
16
|
+
"preview": "<iframe class='tweet-preview' src='https://ton.smf1.twitter.com/ads-manager/tweet-preview/index.html?data=c29tZSByYW5kb20gYmFzZTY0IHN0cmluZ3MgaGVyZS4uLg=='>"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"tweet_id": "1101254234031370240",
|
20
|
+
"preview": "<iframe class='tweet-preview' src='https://ton.smf1.twitter.com/ads-manager/tweet-preview/index.html?data=c29tZSByYW5kb20gYmFzZTY0IHN0cmluZ3MgaGVyZS4uLg=='>"
|
21
|
+
}
|
22
|
+
]
|
23
|
+
}
|
data/spec/spec_helper.rb
CHANGED
@@ -3,12 +3,10 @@
|
|
3
3
|
|
4
4
|
unless RUBY_PLATFORM =~ /java/ || RUBY_ENGINE =~ /rbx/
|
5
5
|
require 'simplecov'
|
6
|
-
require 'codeclimate-test-reporter'
|
7
6
|
|
8
7
|
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
9
8
|
[
|
10
|
-
SimpleCov::Formatter::HTMLFormatter
|
11
|
-
CodeClimate::TestReporter::Formatter
|
9
|
+
SimpleCov::Formatter::HTMLFormatter
|
12
10
|
]
|
13
11
|
)
|
14
12
|
|
@@ -22,7 +20,6 @@ require 'rubocop'
|
|
22
20
|
require 'faker'
|
23
21
|
|
24
22
|
require 'webmock/rspec'
|
25
|
-
WebMock.disable_net_connect!(allow: 'codeclimate.com')
|
26
23
|
|
27
24
|
require 'twitter-ads'
|
28
25
|
include TwitterAds
|
@@ -7,7 +7,12 @@ describe TwitterAds::TailoredAudience do
|
|
7
7
|
|
8
8
|
before(:each) do
|
9
9
|
stub_fixture(:get, :accounts_all, "#{ADS_API}/accounts")
|
10
|
-
stub_fixture(:get,
|
10
|
+
stub_fixture(:get,
|
11
|
+
:tailored_audiences_load,
|
12
|
+
"#{ADS_API}/accounts/2iqph/tailored_audiences/abc2?with_deleted=true")
|
13
|
+
stub_fixture(:get,
|
14
|
+
:targeted_audiences,
|
15
|
+
"#{ADS_API}/accounts/2iqph/tailored_audiences/abc2/targeted")
|
11
16
|
end
|
12
17
|
|
13
18
|
let(:client) do
|
@@ -20,7 +25,7 @@ describe TwitterAds::TailoredAudience do
|
|
20
25
|
end
|
21
26
|
|
22
27
|
let(:account) { client.accounts.first }
|
23
|
-
|
28
|
+
let(:tailored_audience) { described_class.load(account, 'abc2') }
|
24
29
|
# check model properties
|
25
30
|
subject { described_class.new(account) }
|
26
31
|
|
@@ -29,6 +34,7 @@ describe TwitterAds::TailoredAudience do
|
|
29
34
|
created_at
|
30
35
|
updated_at
|
31
36
|
deleted
|
37
|
+
owner_account_id
|
32
38
|
audience_size
|
33
39
|
audience_type
|
34
40
|
metadata
|
@@ -42,4 +48,21 @@ describe TwitterAds::TailoredAudience do
|
|
42
48
|
|
43
49
|
include_examples 'object property check', read, write
|
44
50
|
|
51
|
+
describe '#targeted' do
|
52
|
+
|
53
|
+
let(:cursor) { tailored_audience.targeted }
|
54
|
+
|
55
|
+
it 'has all the correct properties' do
|
56
|
+
result = cursor.first
|
57
|
+
expect(result).to eq(cursor.instance_variable_get('@collection').first)
|
58
|
+
expect(result).to be_instance_of(TwitterAds::TargetedTailoredAudience)
|
59
|
+
expect(cursor).to be_instance_of(Cursor)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises error when TailoredAudience is not loaded' do
|
63
|
+
result = TwitterAds::TailoredAudience.new(account)
|
64
|
+
expect(result).to receive(:validate_loaded).and_call_original
|
65
|
+
expect { result.targeted }.to raise_error(ArgumentError)
|
66
|
+
end
|
67
|
+
end
|
45
68
|
end
|
@@ -21,63 +21,4 @@ describe TwitterAds::Tweet do
|
|
21
21
|
|
22
22
|
let(:account) { client.accounts.first }
|
23
23
|
|
24
|
-
describe '#tweet_preview' do
|
25
|
-
|
26
|
-
let!(:resource_collection) { "#{ADS_API}/accounts/#{account.id}/tweet/preview" }
|
27
|
-
|
28
|
-
before(:each) do
|
29
|
-
stub_fixture(:get, :tweet_preview, /#{resource_collection}.*/)
|
30
|
-
end
|
31
|
-
|
32
|
-
context 'with an existing tweet id' do
|
33
|
-
|
34
|
-
it 'successfully returns a preview of the specified tweet' do
|
35
|
-
params = { id: 634798319504617472 }
|
36
|
-
result = subject.preview(account, params)
|
37
|
-
expect(result.size).not_to be_nil
|
38
|
-
expect(result).to all(include(:platform, :preview))
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
context 'when previewing a new tweet' do
|
44
|
-
|
45
|
-
it 'url encodes the status content' do
|
46
|
-
params = { text: 'Hello World!', card_id: '19v69' }
|
47
|
-
expect(URI).to receive(:escape).at_least(:once).and_call_original
|
48
|
-
result = subject.preview(account, params)
|
49
|
-
expect(result.size).not_to be_nil
|
50
|
-
expect(result).to all(include(:platform, :preview))
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'allows a single value for the media_ids param' do
|
54
|
-
resource = "/#{TwitterAds::API_VERSION}/accounts/#{account.id}/tweet/preview"
|
55
|
-
expected = { text: 'Hello%20World!', media_ids: 634458428836962304 }
|
56
|
-
|
57
|
-
expect(TwitterAds::Request).to receive(:new).with(
|
58
|
-
account.client, :get, resource, params: expected).and_call_original
|
59
|
-
|
60
|
-
params = { text: 'Hello World!', media_ids: 634458428836962304 }
|
61
|
-
result = subject.preview(account, params)
|
62
|
-
expect(result.size).not_to be_nil
|
63
|
-
expect(result).to all(include(:platform, :preview))
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'allows an array of values for the media_ids param' do
|
67
|
-
resource = "/#{TwitterAds::API_VERSION}/accounts/#{account.id}/tweet/preview"
|
68
|
-
expected = { text: 'Hello%20World!', media_ids: '634458428836962304,634458428836962305' }
|
69
|
-
|
70
|
-
expect(TwitterAds::Request).to receive(:new).with(
|
71
|
-
account.client, :get, resource, params: expected).and_call_original
|
72
|
-
|
73
|
-
params = { text: 'Hello World!', media_ids: [634458428836962304, 634458428836962305] }
|
74
|
-
result = subject.preview(account, params)
|
75
|
-
expect(result.size).not_to be_nil
|
76
|
-
expect(result).to all(include(:platform, :preview))
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
24
|
end
|