twitter-ads 5.1.0 → 7.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 +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 -25
- data/lib/twitter-ads/audiences/tailored_audience.rb +98 -3
- 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 +0 -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 +1 -2
- 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 +19 -9
- 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/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/tweet_previews.json +23 -0
- data/spec/spec_helper.rb +1 -4
- data/spec/twitter-ads/campaign/line_item_spec.rb +0 -1
- data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +0 -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/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 +46 -47
- 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
data/lib/twitter-ads/error.rb
CHANGED
@@ -59,18 +59,7 @@ module TwitterAds
|
|
59
59
|
|
60
60
|
# Server Errors (5XX)
|
61
61
|
class ServerError < Error; end
|
62
|
-
|
63
|
-
class ServiceUnavailable < ServerError
|
64
|
-
attr_reader :retry_after
|
65
|
-
|
66
|
-
def initialize(object)
|
67
|
-
super object
|
68
|
-
if object.headers['retry-after']
|
69
|
-
@retry_after = object.headers['retry-after']
|
70
|
-
end
|
71
|
-
self
|
72
|
-
end
|
73
|
-
end
|
62
|
+
class ServiceUnavailable < ServerError; end
|
74
63
|
|
75
64
|
# Client Errors (4XX)
|
76
65
|
class ClientError < Error; end
|
@@ -80,12 +69,13 @@ module TwitterAds
|
|
80
69
|
class BadRequest < ClientError; end
|
81
70
|
|
82
71
|
class RateLimit < ClientError
|
83
|
-
attr_reader :reset_at
|
72
|
+
attr_reader :reset_at
|
84
73
|
|
85
74
|
def initialize(object)
|
86
75
|
super object
|
87
|
-
|
88
|
-
|
76
|
+
header = object.headers.fetch('x-account-rate-limit-reset', nil) ||
|
77
|
+
object.headers.fetch('x-rate-limit-reset', nil)
|
78
|
+
@reset_at = header.first.to_i
|
89
79
|
self
|
90
80
|
end
|
91
81
|
end
|
@@ -71,18 +71,53 @@ module TwitterAds
|
|
71
71
|
token = OAuth::AccessToken.new(consumer, @client.access_token, @client.access_token_secret)
|
72
72
|
request.oauth!(consumer.http, consumer, token)
|
73
73
|
|
74
|
+
handle_rate_limit = @client.options.fetch(:handle_rate_limit, false)
|
75
|
+
retry_max = @client.options.fetch(:retry_max, 0)
|
76
|
+
retry_delay = @client.options.fetch(:retry_delay, 1500)
|
77
|
+
retry_on_status = @client.options.fetch(:retry_on_status, [500, 503])
|
78
|
+
retry_count = 0
|
79
|
+
retry_after = nil
|
80
|
+
|
74
81
|
write_log(request) if @client.options[:trace]
|
75
|
-
|
82
|
+
while retry_count <= retry_max
|
83
|
+
response = consumer.http.request(request)
|
84
|
+
status_code = response.code.to_i
|
85
|
+
break if status_code >= 200 && status_code < 300
|
86
|
+
|
87
|
+
if handle_rate_limit && retry_after.nil?
|
88
|
+
rate_limit_reset = response.fetch('x-account-rate-limit-reset', nil) ||
|
89
|
+
response.fetch('x-rate-limit-reset', nil)
|
90
|
+
if status_code == 429
|
91
|
+
retry_after = rate_limit_reset.to_i - Time.now.to_i
|
92
|
+
@client.logger.warn('Request reached Rate Limit: resume in %d seconds' % retry_after)
|
93
|
+
sleep(retry_after + 5)
|
94
|
+
next
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
if retry_max.positive?
|
99
|
+
break unless retry_on_status.include?(status_code)
|
100
|
+
sleep(retry_delay / 1000)
|
101
|
+
end
|
102
|
+
|
103
|
+
retry_count += 1
|
104
|
+
end
|
76
105
|
write_log(response) if @client.options[:trace]
|
77
106
|
|
78
107
|
Response.new(response.code, response.each {}, response.body)
|
79
108
|
end
|
80
109
|
|
110
|
+
def escape_params(input)
|
111
|
+
input.map do |key, value|
|
112
|
+
"#{CGI.escape key.to_s}=#{CGI.escape value.to_s}"
|
113
|
+
end.join('&')
|
114
|
+
end
|
115
|
+
|
81
116
|
def http_request
|
82
117
|
request_url = @resource
|
83
118
|
|
84
119
|
if @options[:params] && !@options[:params].empty?
|
85
|
-
request_url += "?#{
|
120
|
+
request_url += "?#{escape_params(@options[:params])}"
|
86
121
|
end
|
87
122
|
|
88
123
|
request = HTTP_METHOD[@method].new(request_url)
|
@@ -9,9 +9,7 @@ module TwitterAds
|
|
9
9
|
attr_reader :code,
|
10
10
|
:headers,
|
11
11
|
:raw_body,
|
12
|
-
:body
|
13
|
-
:rate_limit_remaining,
|
14
|
-
:rate_limit_reset
|
12
|
+
:body
|
15
13
|
|
16
14
|
# Creates a new Response object instance.
|
17
15
|
#
|
@@ -37,16 +35,6 @@ module TwitterAds
|
|
37
35
|
@body = raw_body
|
38
36
|
end
|
39
37
|
|
40
|
-
if headers.key?('x-rate-limit-reset')
|
41
|
-
@rate_limit = headers['x-rate-limit-limit'].first
|
42
|
-
@rate_limit_remaining = headers['x-rate-limit-remaining'].first
|
43
|
-
@rate_limit_reset = headers['x-rate-limit-reset'].first.to_i
|
44
|
-
elsif headers.key?('x-cost-rate-limit-reset')
|
45
|
-
@rate_limit = headers['x-cost-rate-limit-limit'].first
|
46
|
-
@rate_limit_remaining = headers['x-cost-rate-limit-remaining'].first
|
47
|
-
@rate_limit_reset = Time.at(headers['x-cost-rate-limit-reset'].first.to_i)
|
48
|
-
end
|
49
|
-
|
50
38
|
self
|
51
39
|
end
|
52
40
|
|
@@ -5,15 +5,35 @@ require 'zlib'
|
|
5
5
|
require 'open-uri'
|
6
6
|
|
7
7
|
module TwitterAds
|
8
|
-
|
8
|
+
class Analytics
|
9
9
|
|
10
|
+
include TwitterAds::DSL
|
11
|
+
include TwitterAds::Resource
|
10
12
|
include TwitterAds::Enum
|
11
13
|
|
14
|
+
attr_reader :account
|
15
|
+
|
16
|
+
property :id, read_only: true
|
17
|
+
property :id_str, read_only: true
|
18
|
+
property :status, read_only: true
|
19
|
+
property :url, read_only: true
|
20
|
+
property :created_at, type: :time, read_only: true
|
21
|
+
property :expires_at, type: :time, read_only: true
|
22
|
+
property :updated_at, type: :time, read_only: true
|
23
|
+
property :start_time, type: :time, read_only: true
|
24
|
+
property :end_time, type: :time, read_only: true
|
25
|
+
|
26
|
+
property :entity, read_only: true
|
27
|
+
property :entity_ids, read_only: true
|
28
|
+
property :placement, read_only: true
|
29
|
+
property :granularity, read_only: true
|
30
|
+
property :metric_groups, read_only: true
|
31
|
+
|
12
32
|
ANALYTICS_MAP = {
|
13
33
|
'TwitterAds::Campaign' => Entity::CAMPAIGN,
|
14
34
|
'TwitterAds::LineItem' => Entity::LINE_ITEM,
|
15
35
|
'TwitterAds::OrganicTweet' => Entity::ORGANIC_TWEET,
|
16
|
-
'TwitterAds::Creative::PromotedAccount' => Entity::
|
36
|
+
'TwitterAds::Creative::PromotedAccount' => Entity::PROMOTED_ACCOUNT,
|
17
37
|
'TwitterAds::Creative::PromotedTweet' => Entity::PROMOTED_TWEET,
|
18
38
|
'TwitterAds::Creative::MediaCreative' => Entity::MEDIA_CREATIVE
|
19
39
|
}.freeze
|
@@ -25,42 +45,38 @@ module TwitterAds
|
|
25
45
|
RESOURCE_ACTIVE_ENTITIES = "/#{TwitterAds::API_VERSION}/" +
|
26
46
|
'stats/accounts/%{account_id}/active_entities' # @api private
|
27
47
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
48
|
+
def initialize(account)
|
49
|
+
@account = account
|
50
|
+
self
|
31
51
|
end
|
32
52
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
def stats(metric_groups, opts = {})
|
52
|
-
self.class.stats(account, [id], metric_groups, opts)
|
53
|
-
end
|
54
|
-
|
53
|
+
# Pulls a list of metrics for the current object instance.
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
# metric_groups = [MetricGroup::MOBILE_CONVERSION, MetricGroup::ENGAGEMENT]
|
57
|
+
# object.stats(metrics)
|
58
|
+
#
|
59
|
+
# @param metric_groups [Array] A collection of metric groups to fetch.
|
60
|
+
# @param opts [Hash] An optional Hash of extended options.
|
61
|
+
# @option opts [Time] :start_time The starting time to use (default: 7 days ago).
|
62
|
+
# @option opts [Time] :end_time The end time to use (default: now).
|
63
|
+
# @option opts [Symbol] :granularity The granularity to use (default: :hour).
|
64
|
+
#
|
65
|
+
# @return [Array] The collection of stats requested.
|
66
|
+
#
|
67
|
+
# @see https://dev.twitter.com/ads/analytics/metrics-and-segmentation
|
68
|
+
# @since 1.0.0
|
69
|
+
def stats(metric_groups, opts = {})
|
70
|
+
self.class.stats(account, [id], metric_groups, opts)
|
55
71
|
end
|
56
72
|
|
57
|
-
|
73
|
+
class << self
|
58
74
|
|
59
75
|
# Pulls a list of metrics for a specified set of object IDs.
|
60
76
|
#
|
61
77
|
# @example
|
62
78
|
# ids = ['7o4em', 'oc9ce', '1c5lji']
|
63
|
-
# metric_groups = [
|
79
|
+
# metric_groups = [MetricGroup::MOBILE_CONVERSION, MetricGroup::ENGAGEMENT]
|
64
80
|
# object.stats(account, ids, metric_groups)
|
65
81
|
#
|
66
82
|
# @param account [Account] The Account object instance.
|
@@ -70,7 +86,7 @@ module TwitterAds
|
|
70
86
|
# @option opts [Time] :start_time The starting time to use (default: 7 days ago).
|
71
87
|
# @option opts [Time] :end_time The end time to use (default: now).
|
72
88
|
# @option opts [Symbol] :granularity The granularity to use (default: :hour).
|
73
|
-
# @option opts [
|
89
|
+
# @option opts [String] :placement The placement of entity (default: ALL_ON_TWITTER).
|
74
90
|
#
|
75
91
|
# @return [Array] The collection of stats requested.
|
76
92
|
#
|
@@ -108,7 +124,7 @@ module TwitterAds
|
|
108
124
|
#
|
109
125
|
# @example
|
110
126
|
# ids = ['7o4em', 'oc9ce', '1c5lji']
|
111
|
-
# metric_groups = [
|
127
|
+
# metric_groups = [MetricGroup::MOBILE_CONVERSION, MetricGroup::ENGAGEMENT]
|
112
128
|
# object.create_async_job(account, ids, metric_groups)
|
113
129
|
#
|
114
130
|
# @param account [Account] The Account object instance.
|
@@ -118,16 +134,17 @@ module TwitterAds
|
|
118
134
|
# @option opts [Time] :start_time The starting time to use (default: 7 days ago).
|
119
135
|
# @option opts [Time] :end_time The end time to use (default: now).
|
120
136
|
# @option opts [Symbol] :granularity The granularity to use (default: :hour).
|
121
|
-
# @option opts [
|
122
|
-
# @option opts [
|
137
|
+
# @option opts [String] :placement The placement of entity (default: ALL_ON_TWITTER).
|
138
|
+
# @option opts [String] :segmentation_type The segmentation type to use (default: none).
|
123
139
|
#
|
124
140
|
# @return The response of creating job
|
125
141
|
#
|
126
142
|
# @see https://dev.twitter.com/ads/analytics/metrics-and-segmentation
|
127
|
-
# @
|
143
|
+
# @since 1.0.0
|
128
144
|
|
129
145
|
def create_async_job(account, ids, metric_groups, opts = {})
|
130
146
|
# set default metric values
|
147
|
+
entity = opts.fetch(:entity, name)
|
131
148
|
end_time = opts.fetch(:end_time, (Time.now - Time.now.sec - (60 * Time.now.min)))
|
132
149
|
start_time = opts.fetch(:start_time, end_time - 604_800) # 7 days ago
|
133
150
|
granularity = opts.fetch(:granularity, :hour)
|
@@ -143,7 +160,7 @@ module TwitterAds
|
|
143
160
|
start_time: TwitterAds::Utils.to_time(start_time, granularity, start_utc_offset),
|
144
161
|
end_time: TwitterAds::Utils.to_time(end_time, granularity, end_utc_offset),
|
145
162
|
granularity: granularity.to_s.upcase,
|
146
|
-
entity: ANALYTICS_MAP[
|
163
|
+
entity: ANALYTICS_MAP[entity],
|
147
164
|
placement: placement,
|
148
165
|
country: country,
|
149
166
|
platform: platform
|
@@ -153,19 +170,18 @@ module TwitterAds
|
|
153
170
|
params['entity_ids'] = ids.join(',')
|
154
171
|
|
155
172
|
resource = self::RESOURCE_ASYNC_STATS % { account_id: account.id }
|
156
|
-
puts 'my resource is ' + resource
|
157
173
|
response = Request.new(account.client, :post, resource, params: params).perform
|
158
|
-
response.body[:data]
|
174
|
+
TwitterAds::Analytics.new(account).from_response(response.body[:data], response.headers)
|
159
175
|
end
|
160
176
|
|
161
177
|
# Check async job status.
|
162
178
|
# GET /#{TwitterAds::API_VERSION}/stats/jobs/accounts/:account_id
|
163
179
|
#
|
164
180
|
# @example
|
165
|
-
# TwitterAds::LineItem.check_async_job_status(account,
|
181
|
+
# TwitterAds::LineItem.check_async_job_status(account, job_ids: ['1357343438724431305'])
|
166
182
|
#
|
167
183
|
# @param account [Account] The Account object instance.
|
168
|
-
# @option opts [
|
184
|
+
# @option opts [Array] :job_ids A collection of job IDs to fetch.
|
169
185
|
#
|
170
186
|
# @return A cursor of job statuses
|
171
187
|
|
@@ -173,18 +189,18 @@ module TwitterAds
|
|
173
189
|
# set default values
|
174
190
|
job_ids = opts.fetch(:job_ids, nil)
|
175
191
|
params = {}
|
176
|
-
params[:job_ids] =
|
192
|
+
params[:job_ids] = job_ids.join(',') if job_ids
|
177
193
|
|
178
194
|
resource = self::RESOURCE_ASYNC_STATS % { account_id: account.id }
|
179
195
|
request = Request.new(account.client, :get, resource, params: params)
|
180
|
-
Cursor.new(
|
196
|
+
Cursor.new(TwitterAds::Analytics, request, init_with: [account])
|
181
197
|
end
|
182
198
|
|
183
199
|
# Fetch async job data for a completed job.
|
184
200
|
# Raises HTTP 404 exception, otherwise retries up to 5 times with exponential backoff.
|
185
201
|
#
|
186
202
|
# @example
|
187
|
-
# response_data = TwitterAds::LineItem.fetch_async_job_data(account,
|
203
|
+
# response_data = TwitterAds::LineItem.fetch_async_job_data(account, data_url)
|
188
204
|
#
|
189
205
|
# @param data_url [String] The URL from the successful completion of an async job.
|
190
206
|
#
|
@@ -209,21 +225,57 @@ module TwitterAds
|
|
209
225
|
end
|
210
226
|
end
|
211
227
|
|
228
|
+
# Retrieve details about which entities' analytics metrics
|
229
|
+
# have changed in a given time period.
|
230
|
+
#
|
231
|
+
# @example
|
232
|
+
# time = Time.now
|
233
|
+
# utc_offset = '+09:00'
|
234
|
+
# start_time = time - (60 * 60 * 24) # -1 day
|
235
|
+
# end_time = time
|
236
|
+
# active_entities = TwitterAds::LineItem.active_entities(
|
237
|
+
# account,
|
238
|
+
# line_item_ids: %w(exrfs),
|
239
|
+
# start_time: start_time,
|
240
|
+
# end_time: end_time,
|
241
|
+
# utc_offset: utc_offset,
|
242
|
+
# granularity: :day)
|
243
|
+
#
|
244
|
+
# @param account [Account] The Account object instance.
|
245
|
+
# @param entity [String] The entity type to retrieve data for.
|
246
|
+
# @param start_time [Time] Scopes the retrieved data to the specified start time.
|
247
|
+
# @param end_time [Time] Scopes the retrieved data to the specified end time.
|
248
|
+
# @option opts [Array] :campaign_ids A collection of IDs to be fetched.
|
249
|
+
# @option opts [Array] :funding_instrument_ids A collection of IDs to be fetched.
|
250
|
+
# @option opts [Array] :line_item_ids A collection of IDs to be fetched.
|
251
|
+
#
|
252
|
+
# @return A list of entity details.
|
253
|
+
#
|
254
|
+
# @see https://developer.twitter.com/en/docs/ads/analytics/api-reference/active-entities
|
255
|
+
|
212
256
|
def active_entities(account, start_time:, end_time:, **opts)
|
213
|
-
|
257
|
+
entity = opts.fetch(:entity, name)
|
214
258
|
granularity = opts.fetch(:granularity, nil)
|
215
259
|
start_utc_offset = opts[:start_utc_offset] || opts[:utc_offset]
|
216
260
|
end_utc_offset = opts[:end_utc_offset] || opts[:utc_offset]
|
217
261
|
|
218
|
-
if
|
219
|
-
raise "'OrganicTweet' not
|
262
|
+
if entity == 'OrganicTweet'
|
263
|
+
raise "'OrganicTweet' is not supported with 'active_entities'"
|
220
264
|
end
|
221
265
|
|
222
266
|
params = {
|
223
|
-
entity: ANALYTICS_MAP[
|
267
|
+
entity: ANALYTICS_MAP[entity],
|
224
268
|
start_time: TwitterAds::Utils.to_time(start_time, granularity, start_utc_offset),
|
225
269
|
end_time: TwitterAds::Utils.to_time(end_time, granularity, end_utc_offset)
|
226
|
-
}
|
270
|
+
}
|
271
|
+
|
272
|
+
opts.each { |k, v|
|
273
|
+
params[k] = if v.instance_of?(Array)
|
274
|
+
v.join(',')
|
275
|
+
else
|
276
|
+
v
|
277
|
+
end
|
278
|
+
}
|
227
279
|
|
228
280
|
resource = self::RESOURCE_ACTIVE_ENTITIES % { account_id: account.id }
|
229
281
|
response = Request.new(account.client, :get, resource, params: params).perform
|
@@ -20,7 +20,14 @@ module TwitterAds
|
|
20
20
|
# @return [self] A fully hydrated instance of the current class.
|
21
21
|
#
|
22
22
|
# @since 0.1.0
|
23
|
-
def from_response(object)
|
23
|
+
def from_response(object, headers = nil)
|
24
|
+
if !headers.nil?
|
25
|
+
TwitterAds::Utils.extract_response_headers(headers).each { |key, value|
|
26
|
+
singleton_class.class_eval { attr_accessor key }
|
27
|
+
instance_variable_set("@#{key}", value)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
24
31
|
self.class.properties.each do |name, type|
|
25
32
|
value = nil
|
26
33
|
if type == :time && object[name] && !object[name].empty?
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright (C) 2019 Twitter, Inc.
|
3
|
+
|
4
|
+
module TwitterRestApi
|
5
|
+
class UserIdLookup
|
6
|
+
include TwitterAds::DSL
|
7
|
+
include TwitterAds::Resource
|
8
|
+
|
9
|
+
attr_reader :account
|
10
|
+
|
11
|
+
property :id, read_only: true
|
12
|
+
property :id_str, read_only: true
|
13
|
+
property :screen_name, read_only: true
|
14
|
+
|
15
|
+
DOMAIN = 'https://api.twitter.com'
|
16
|
+
RESOURCE = '/1.1/users/show.json'
|
17
|
+
|
18
|
+
def self.load(account, opts = {})
|
19
|
+
response = TwitterAds::Request.new(
|
20
|
+
account.client,
|
21
|
+
:get,
|
22
|
+
RESOURCE,
|
23
|
+
params: opts,
|
24
|
+
domain: DOMAIN
|
25
|
+
).perform
|
26
|
+
new.from_response(response.body, response.headers)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -41,12 +41,24 @@ module TwitterAds
|
|
41
41
|
property :to_delete, type: :bool
|
42
42
|
|
43
43
|
RESOURCE = "/#{TwitterAds::API_VERSION}/" \
|
44
|
-
'accounts/%{account_id}/
|
44
|
+
'accounts/%{account_id}/tax_settings' # @api private
|
45
45
|
|
46
46
|
def initialize(account)
|
47
47
|
@account = account
|
48
48
|
self
|
49
49
|
end
|
50
50
|
|
51
|
+
def self.load(account)
|
52
|
+
resource = RESOURCE % { account_id: account.id }
|
53
|
+
response = Request.new(account.client, :get, resource).perform
|
54
|
+
new(account).from_response(response.body[:data])
|
55
|
+
end
|
56
|
+
|
57
|
+
def save
|
58
|
+
resource = RESOURCE % { account_id: account.id }
|
59
|
+
params = to_params
|
60
|
+
response = Request.new(account.client, :put, resource, params: params).perform
|
61
|
+
from_response(response.body[:data])
|
62
|
+
end
|
51
63
|
end
|
52
64
|
end
|