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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -2
  3. data/README.md +1 -1
  4. data/lib/twitter-ads.rb +8 -4
  5. data/lib/twitter-ads/account.rb +6 -25
  6. data/lib/twitter-ads/audiences/tailored_audience.rb +98 -3
  7. data/lib/twitter-ads/{targeting_criteria/behavior_taxonomy.rb → campaign/advertiser_business_categories.rb} +6 -6
  8. data/lib/twitter-ads/campaign/campaign.rb +1 -2
  9. data/lib/twitter-ads/campaign/content_categories.rb +23 -0
  10. data/lib/twitter-ads/campaign/funding_instrument.rb +1 -2
  11. data/lib/twitter-ads/campaign/line_item.rb +4 -4
  12. data/lib/twitter-ads/campaign/organic_tweet.rb +1 -3
  13. data/lib/twitter-ads/campaign/targeting_criteria.rb +0 -1
  14. data/lib/twitter-ads/campaign/tweet.rb +4 -49
  15. data/lib/twitter-ads/client.rb +2 -2
  16. data/lib/twitter-ads/creative/account_media.rb +4 -6
  17. data/lib/twitter-ads/creative/draft_tweet.rb +40 -0
  18. data/lib/twitter-ads/creative/image_app_download_card.rb +2 -2
  19. data/lib/twitter-ads/creative/image_conversation_card.rb +3 -2
  20. data/lib/twitter-ads/creative/media_creative.rb +2 -3
  21. data/lib/twitter-ads/creative/media_library.rb +12 -13
  22. data/lib/twitter-ads/creative/promoted_account.rb +1 -2
  23. data/lib/twitter-ads/creative/promoted_tweet.rb +1 -2
  24. data/lib/twitter-ads/creative/scheduled_tweet.rb +1 -12
  25. data/lib/twitter-ads/creative/tweets.rb +52 -0
  26. data/lib/twitter-ads/creative/video_app_download_card.rb +4 -6
  27. data/lib/twitter-ads/creative/video_conversation_card.rb +6 -6
  28. data/lib/twitter-ads/creative/video_website_card.rb +3 -5
  29. data/lib/twitter-ads/creative/website_card.rb +2 -2
  30. data/lib/twitter-ads/cursor.rb +6 -0
  31. data/lib/twitter-ads/enum.rb +19 -9
  32. data/lib/twitter-ads/error.rb +5 -15
  33. data/lib/twitter-ads/http/request.rb +37 -2
  34. data/lib/twitter-ads/http/response.rb +1 -13
  35. data/lib/twitter-ads/resources/analytics.rb +99 -47
  36. data/lib/twitter-ads/resources/dsl.rb +8 -1
  37. data/lib/twitter-ads/restapi.rb +29 -0
  38. data/lib/twitter-ads/settings/tax.rb +13 -1
  39. data/lib/twitter-ads/targeting/audience_summary.rb +47 -0
  40. data/lib/twitter-ads/targeting_criteria/{behavior.rb → conversation.rb} +3 -7
  41. data/lib/twitter-ads/utils.rb +23 -0
  42. data/lib/twitter-ads/version.rb +1 -1
  43. data/spec/fixtures/audience_summary.json +14 -0
  44. data/spec/fixtures/line_items_all.json +2 -10
  45. data/spec/fixtures/line_items_load.json +0 -1
  46. data/spec/fixtures/tweet_previews.json +23 -0
  47. data/spec/spec_helper.rb +1 -4
  48. data/spec/twitter-ads/campaign/line_item_spec.rb +0 -1
  49. data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +0 -1
  50. data/spec/twitter-ads/campaign/tweet_spec.rb +0 -59
  51. data/spec/twitter-ads/client_spec.rb +17 -1
  52. data/spec/twitter-ads/creative/media_creative_spec.rb +1 -1
  53. data/spec/twitter-ads/creative/tweet_previews_spec.rb +41 -0
  54. data/spec/twitter-ads/rate_limit_spec.rb +247 -0
  55. data/spec/twitter-ads/retry_count_spec.rb +61 -0
  56. data/spec/twitter-ads/{creative/image_app_download_card_spec.rb → targeting/audience_summary_spec.rb} +16 -18
  57. metadata +46 -47
  58. data/lib/twitter-ads/audiences/audience_intelligence.rb +0 -68
  59. data/lib/twitter-ads/targeting/reach_estimate.rb +0 -78
  60. data/spec/fixtures/tweet_preview.json +0 -24
  61. data/spec/twitter-ads/campaign/reach_estimate_spec.rb +0 -103
  62. data/spec/twitter-ads/creative/account_media_spec.rb +0 -32
  63. data/spec/twitter-ads/creative/image_conversation_card_spec.rb +0 -40
  64. data/spec/twitter-ads/creative/video_app_download_card_spec.rb +0 -42
  65. data/spec/twitter-ads/creative/video_conversation_card_spec.rb +0 -51
  66. data/spec/twitter-ads/creative/website_card_spec.rb +0 -42
@@ -3,7 +3,7 @@
3
3
 
4
4
  module TwitterAds
5
5
 
6
- API_VERSION = '5'
6
+ API_VERSION = '7'
7
7
 
8
8
  # The Ads API Client class which functions as a
9
9
  # container for basic API consumer information.
@@ -34,7 +34,7 @@ module TwitterAds
34
34
  @consumer_secret = consumer_secret
35
35
  @access_token = access_token
36
36
  @access_token_secret = access_token_secret
37
- @options = opts
37
+ @options = opts.fetch(:options, {})
38
38
  validate
39
39
  self
40
40
  end
@@ -12,15 +12,13 @@ module TwitterAds
12
12
 
13
13
  attr_reader :account
14
14
 
15
- property :created_at, type: :time, read_only: true
16
15
  property :deleted, type: :bool, read_only: true
16
+ property :created_at, type: :time, read_only: true
17
+ property :updated_at, type: :time, read_only: true
17
18
  property :id, read_only: true
19
+ property :creative_type, read_only: true
20
+ property :media_key, read_only: true
18
21
  property :media_url, read_only: true
19
- property :updated_at, type: :time, read_only: true
20
-
21
- property :creative_type
22
- property :media_id
23
- property :video_id
24
22
 
25
23
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
26
24
  'accounts/%{account_id}/account_media' # @api private
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2019 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ module Creative
6
+
7
+ class DraftTweet
8
+
9
+ include TwitterAds::DSL
10
+ include TwitterAds::Resource
11
+ include TwitterAds::Persistence
12
+
13
+ attr_reader :account
14
+
15
+ # read-only
16
+ property :id, read_only: true
17
+ property :id_str, read_only: true
18
+ property :created_at, type: :time, read_only: true
19
+ property :updated_at, type: :time, read_only: true
20
+ property :user_id, read_only: true
21
+ # writable
22
+ property :as_user_id
23
+ property :card_uri
24
+ property :media_keys
25
+ property :nullcast, type: :bool
26
+ property :text
27
+
28
+ RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
29
+ 'accounts/%{account_id}/draft_tweets' # @api private
30
+ RESOURCE = "/#{TwitterAds::API_VERSION}/" \
31
+ 'accounts/%{account_id}/draft_tweets/%{id}' # @api private
32
+
33
+ def initialize(account)
34
+ @account = account
35
+ self
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -20,7 +20,7 @@ module TwitterAds
20
20
  property :image_display_height, read_only: true
21
21
  property :image_display_width, read_only: true
22
22
  property :updated_at, type: :time, read_only: true
23
- property :wide_app_image, read_only: true
23
+ property :media_url, read_only: true
24
24
 
25
25
  property :country_code
26
26
  property :app_cta
@@ -31,7 +31,7 @@ module TwitterAds
31
31
  property :ipad_app_id
32
32
  property :ipad_deep_link
33
33
  property :name
34
- property :wide_app_image_media_id
34
+ property :media_key
35
35
 
36
36
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
37
37
  'accounts/%{account_id}/cards/image_app_download' # @api private
@@ -19,13 +19,14 @@ module TwitterAds
19
19
  property :id, read_only: true
20
20
  property :image, read_only: true
21
21
  property :updated_at, type: :time, read_only: true
22
+ property :media_url, read_only: true
22
23
 
23
- property :cover_image_id
24
+ property :unlocked_image_media_key
24
25
  property :first_cta
25
26
  property :first_cta_tweet
26
27
  property :fourth_cta
27
28
  property :fourth_cta_tweet
28
- property :image_media_id
29
+ property :media_key
29
30
  property :name
30
31
  property :second_cta
31
32
  property :second_cta_tweet
@@ -4,12 +4,11 @@
4
4
  module TwitterAds
5
5
  module Creative
6
6
 
7
- class MediaCreative
7
+ class MediaCreative < Analytics
8
8
 
9
9
  include TwitterAds::DSL
10
10
  include TwitterAds::Resource
11
11
  include TwitterAds::Persistence
12
- include TwitterAds::Analytics
13
12
 
14
13
  attr_reader :account
15
14
 
@@ -17,7 +16,7 @@ module TwitterAds
17
16
  property :created_at, type: :time, read_only: true
18
17
  property :deleted, type: :bool, read_only: true
19
18
  property :id, read_only: true
20
- property :serving_status, read_only: true
19
+ property :entity_status, read_only: true
21
20
  property :updated_at, type: :time, read_only: true
22
21
 
23
22
  property :account_media_id
@@ -22,17 +22,14 @@ module TwitterAds
22
22
  property :media_url, read_only: true
23
23
  property :tweeted, type: :bool, read_only: true
24
24
  property :updated_at, type: :time, read_only: true
25
- property :poster_image_url, read_only: true
25
+ property :poster_media_url, read_only: true
26
26
 
27
27
  # writable
28
- property :media_category
29
- property :media_id
30
28
  property :media_key
31
29
  property :description
32
30
  property :file_name
33
31
  property :name
34
- property :poster_image_media_id
35
- property :poster_image_media_key
32
+ property :poster_media_key
36
33
  property :title
37
34
 
38
35
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
@@ -48,15 +45,17 @@ module TwitterAds
48
45
  end
49
46
  end
50
47
 
51
- def save
48
+ def add
52
49
  params = to_params
53
- if @media_key
54
- resource = self.class::RESOURCE % { account_id: account.id, id: media_key }
55
- response = Request.new(account.client, :put, resource, params: params).perform
56
- else
57
- resource = self.class::RESOURCE_COLLECTION % { account_id: account.id }
58
- response = Request.new(account.client, :post, resource, params: params).perform
59
- end
50
+ resource = self.class::RESOURCE_COLLECTION % { account_id: account.id }
51
+ response = Request.new(account.client, :post, resource, params: params).perform
52
+ from_response(response.body[:data])
53
+ end
54
+
55
+ def update
56
+ params = to_params
57
+ resource = self.class::RESOURCE % { account_id: account.id, id: media_key }
58
+ response = Request.new(account.client, :put, resource, params: params).perform
60
59
  from_response(response.body[:data])
61
60
  end
62
61
 
@@ -4,12 +4,11 @@
4
4
  module TwitterAds
5
5
  module Creative
6
6
 
7
- class PromotedAccount
7
+ class PromotedAccount < Analytics
8
8
 
9
9
  include TwitterAds::DSL
10
10
  include TwitterAds::Resource
11
11
  include TwitterAds::Persistence
12
- include TwitterAds::Analytics
13
12
 
14
13
  attr_reader :account
15
14
 
@@ -4,12 +4,11 @@
4
4
  module TwitterAds
5
5
  module Creative
6
6
 
7
- class PromotedTweet
7
+ class PromotedTweet < Analytics
8
8
 
9
9
  include TwitterAds::DSL
10
10
  include TwitterAds::Resource
11
11
  include TwitterAds::Persistence
12
- include TwitterAds::Analytics
13
12
 
14
13
  attr_reader :account
15
14
 
@@ -17,7 +17,6 @@ module TwitterAds
17
17
  property :created_at, type: :time, read_only: true
18
18
  property :id, read_only: true
19
19
  property :id_str, read_only: true
20
- property :media_keys, read_only: true
21
20
  property :scheduled_status, read_only: true
22
21
  property :tweet_id, read_only: true
23
22
  property :updated_at, type: :time, read_only: true
@@ -26,7 +25,7 @@ module TwitterAds
26
25
  # writable
27
26
  property :as_user_id
28
27
  property :card_uri
29
- property :media_ids
28
+ property :media_keys
30
29
  property :nullcast, type: :bool
31
30
  property :scheduled_at, type: :time
32
31
  property :text
@@ -35,16 +34,6 @@ module TwitterAds
35
34
  'accounts/%{account_id}/scheduled_tweets' # @api private
36
35
  RESOURCE = "/#{TwitterAds::API_VERSION}/" \
37
36
  'accounts/%{account_id}/scheduled_tweets/%{id}' # @api private
38
- PREVIEW = "/#{TwitterAds::API_VERSION}/" \
39
- 'accounts/%{account_id}/scheduled_tweets/preview/%{id}' # @api private
40
-
41
- def preview(account, opts = {})
42
- if @id
43
- resource = self.class::PREVIEW % { account_id: account.id, id: id }
44
- response = TwitterAds::Request.new(account.client, :get, resource, params: opts).perform
45
- response.body[:data]
46
- end
47
- end
48
37
 
49
38
  def initialize(account)
50
39
  @account = account
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2019 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ module Creative
6
+
7
+ class Tweets
8
+
9
+ include TwitterAds::DSL
10
+ include TwitterAds::Resource
11
+
12
+ attr_reader :account
13
+
14
+ RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" +
15
+ 'accounts/%{account_id}/tweets' # @api private
16
+
17
+ # Retrieve Tweet details for the account's full promotable user (default)
18
+ # or the user specified in the user_id parameter.
19
+ #
20
+ # @example
21
+ # tweets = TwitterAds::Creative::Tweets.all(
22
+ # account,
23
+ # tweet_type: 'PUBLISHED',
24
+ # tweet_ids: %w(1122911801354510336 1102836745790316550),
25
+ # timeline_type: 'ORGANIC'
26
+ # )
27
+ #
28
+ # @param account [Account] The Account object instance.
29
+ # @param tweet_type [String] The Tweet type for the specified tweet_ids.
30
+ # @option opts [Int] :count The number of records to try and retrieve per distinct request.
31
+ # @option opts [String] :cursor A cursor to get the next page of results.
32
+ # @option opts [String] :timeline_type The granularity to use (default: NULLCAST).
33
+ # @option opts [Boolean] :trim_user Whether to exclude the user object
34
+ # in the Tweet response (default: false).
35
+ # @option opts [Array] :tweet_ids A collection of tweet IDs to be fetched.
36
+ # @option opts [Long] :user_id The user ID to scope Tweets to.
37
+ #
38
+ # @return A list of tweets details.
39
+ #
40
+ # @see https://developer.twitter.com/en/docs/ads/creatives/api-reference/tweets#get-accounts-account-id-tweets
41
+ # @since 6.0.0
42
+
43
+ def self.all(account, opts = {})
44
+ params = TwitterAds::Utils.flatten_params(opts)
45
+ resource = self::RESOURCE_COLLECTION % { account_id: account.id }
46
+ request = Request.new(account.client, :get, resource, params: params)
47
+ Cursor.new(nil, request, init_with: [account])
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -18,15 +18,13 @@ module TwitterAds
18
18
  property :deleted, type: :bool, read_only: true
19
19
  property :id, read_only: true
20
20
  property :updated_at, type: :time, read_only: true
21
- property :video_content_id, read_only: true
22
- property :video_hls_url, read_only: true
23
21
  property :video_owner_id, read_only: true
24
- property :video_poster_url, read_only: true
25
- property :video_url, read_only: true
22
+ property :poster_media_url, read_only: true
23
+ property :media_url, read_only: true
26
24
 
27
25
  property :country_code
28
26
  property :app_cta
29
- property :image_media_id
27
+ property :poster_media_key
30
28
  property :ipad_app_id
31
29
  property :ipad_deep_link
32
30
  property :iphone_app_id
@@ -34,7 +32,7 @@ module TwitterAds
34
32
  property :googleplay_app_id
35
33
  property :googleplay_deep_link
36
34
  property :name
37
- property :video_id
35
+ property :media_key
38
36
 
39
37
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
40
38
  'accounts/%{account_id}/cards/video_app_download' # @api private
@@ -18,14 +18,14 @@ module TwitterAds
18
18
  property :deleted, type: :bool, read_only: true
19
19
  property :id, read_only: true
20
20
  property :updated_at, type: :time, read_only: true
21
- property :video_url, read_only: true
22
- property :video_poster_url, read_only: true
21
+ property :media_url, read_only: true
22
+ property :poster_media_url, read_only: true
23
23
 
24
- property :cover_image_id
25
- property :cover_video_id
24
+ property :unlocked_image_media_key
25
+ property :unlocked_video_media_key
26
26
  property :fourth_cta
27
27
  property :fourth_cta_tweet
28
- property :image_media_id
28
+ property :poster_media_key
29
29
  property :first_cta
30
30
  property :first_cta_tweet
31
31
  property :name
@@ -36,7 +36,7 @@ module TwitterAds
36
36
  property :third_cta
37
37
  property :third_cta_tweet
38
38
  property :title
39
- property :video_id
39
+ property :media_key
40
40
 
41
41
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
42
42
  'accounts/%{account_id}/cards/video_conversation' # @api private
@@ -19,21 +19,19 @@ module TwitterAds
19
19
  property :deleted, type: :bool, read_only: true
20
20
  property :id, read_only: true
21
21
  property :updated_at, type: :time, read_only: true
22
- property :video_content_id, read_only: true
23
22
  property :video_height, read_only: true
24
- property :video_hls_url, read_only: true
25
23
  property :video_owner_id, read_only: true
26
24
  property :video_poster_height, read_only: true
27
- property :video_poster_url, read_only: true
25
+ property :poster_media_url, read_only: true
28
26
  property :video_poster_width, read_only: true
29
- property :video_url, read_only: true
27
+ property :media_url, read_only: true
30
28
  property :video_width, read_only: true
31
29
  property :website_display_url, read_only: true
32
30
  property :website_dest_url, read_only: true
33
31
 
34
32
  property :name
35
33
  property :title
36
- property :video_id
34
+ property :media_key
37
35
  property :website_url
38
36
 
39
37
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/accounts/%{account_id}/cards/video_website"
@@ -17,14 +17,14 @@ module TwitterAds
17
17
  property :created_at, type: :time, read_only: true
18
18
  property :deleted, type: :bool, read_only: true
19
19
  property :id, read_only: true
20
- property :image, read_only: true
20
+ property :media_url, read_only: true
21
21
  property :image_display_height, read_only: true
22
22
  property :image_display_width, read_only: true
23
23
  property :updated_at, type: :time, read_only: true
24
24
  property :website_dest_url, read_only: true
25
25
  property :website_display_url, read_only: true
26
26
 
27
- property :image_media_id
27
+ property :media_key
28
28
  property :name
29
29
  property :website_title
30
30
  property :website_url
@@ -112,6 +112,12 @@ module TwitterAds
112
112
  def from_response(response)
113
113
  @next_cursor = response.body[:next_cursor]
114
114
  @total_count = response.body[:total_count].to_i if response.body.key?(:total_count)
115
+
116
+ TwitterAds::Utils.extract_response_headers(response.headers).each { |key, value|
117
+ singleton_class.class_eval { attr_accessor key }
118
+ instance_variable_set("@#{key}", value)
119
+ }
120
+
115
121
  response.body.fetch(:data, []).each do |object|
116
122
  @collection << if @klass&.method_defined?(:from_response)
117
123
  @klass.new(
@@ -24,10 +24,15 @@ module TwitterAds
24
24
  end
25
25
 
26
26
  module Placement
27
- ALL_ON_TWITTER = 'ALL_ON_TWITTER'
28
- TWITTER_SEARCH = 'TWITTER_SEARCH'
29
- TWITTER_TIMELINE = 'TWITTER_TIMELINE'
30
- PUBLISHER_NETWORK = 'PUBLISHER_NETWORK'
27
+ ALL_ON_TWITTER = 'ALL_ON_TWITTER'
28
+ TWITTER_SEARCH = 'TWITTER_SEARCH'
29
+ TWITTER_TIMELINE = 'TWITTER_TIMELINE'
30
+ PUBLISHER_NETWORK = 'PUBLISHER_NETWORK'
31
+ TAP_FULL = 'TAP_FULL'
32
+ TAP_FULL_LANDSCAPE = 'TAP_FULL_LANDSCAPE'
33
+ TAP_BANNER = 'TAP_BANNER'
34
+ TAP_NATIVE = 'TAP_NATIVE'
35
+ TAP_MRECT = 'TAP_MRECT'
31
36
  end
32
37
 
33
38
  module Placement
@@ -106,6 +111,7 @@ module TwitterAds
106
111
  FUNDING_INSTRUMENT = 'FUNDING_INSTRUMENT'
107
112
  CAMPAIGN = 'CAMPAIGN'
108
113
  LINE_ITEM = 'LINE_ITEM'
114
+ PROMOTED_ACCOUNT = 'PROMOTED_ACCOUNT'
109
115
  PROMOTED_TWEET = 'PROMOTED_TWEET'
110
116
  ORGANIC_TWEET = 'ORGANIC_TWEET'
111
117
  MEDIA_CREATIVE = 'MEDIA_CREATIVE'
@@ -143,7 +149,10 @@ module TwitterAds
143
149
  end
144
150
 
145
151
  module Optimizations
152
+ APP_CLICKS = 'APP_CLICKS'
153
+ APP_INSTALLS = 'APP_INSTALLS'
146
154
  DEFAULT = 'DEFAULT'
155
+ ENGAGEMENTS = 'ENGAGEMENTS'
147
156
  WEBSITE_CONVERSIONS = 'WEBSITE_CONVERSIONS'
148
157
  end
149
158
 
@@ -218,11 +227,6 @@ module TwitterAds
218
227
  HASHTAG = 'HASHTAG'
219
228
  end
220
229
 
221
- module AudienceDefinition
222
- TARGETING_CRITERIA = 'TARGETING_CRITERIA'
223
- KEYWORD_AUDIENCE = 'KEYWORD_AUDIENCE'
224
- end
225
-
226
230
  module LookalikeExpansion
227
231
  DEFINED = 'DEFINED'
228
232
  EXPANDED = 'EXPANDED'
@@ -233,5 +237,11 @@ module TwitterAds
233
237
  PUBLISHED = 'PUBLISHED'
234
238
  SCHEDULED = 'SCHEDULED'
235
239
  end
240
+
241
+ module TimelineType
242
+ ALL = 'ALL'
243
+ NULLCAST = 'NULLCAST'
244
+ ORGANIC = 'ORGANIC'
245
+ end
236
246
  end
237
247
  end