twitter-ads 5.2.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) 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 -24
  6. data/lib/twitter-ads/audiences/tailored_audience.rb +56 -1
  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 +1 -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 +2 -3
  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 +22 -13
  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/targeting_criteria/event.rb +1 -0
  42. data/lib/twitter-ads/utils.rb +23 -0
  43. data/lib/twitter-ads/version.rb +1 -1
  44. data/spec/fixtures/audience_summary.json +14 -0
  45. data/spec/fixtures/line_items_all.json +2 -10
  46. data/spec/fixtures/line_items_load.json +0 -1
  47. data/spec/fixtures/tailored_audiences_all.json +3 -0
  48. data/spec/fixtures/targeted_audiences.json +33 -0
  49. data/spec/fixtures/tweet_previews.json +23 -0
  50. data/spec/spec_helper.rb +1 -4
  51. data/spec/twitter-ads/audiences/tailored_audience_spec.rb +25 -2
  52. data/spec/twitter-ads/campaign/line_item_spec.rb +0 -1
  53. data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +1 -1
  54. data/spec/twitter-ads/campaign/tweet_spec.rb +0 -59
  55. data/spec/twitter-ads/client_spec.rb +17 -1
  56. data/spec/twitter-ads/creative/media_creative_spec.rb +1 -1
  57. data/spec/twitter-ads/creative/promoted_tweet_spec.rb +18 -0
  58. data/spec/twitter-ads/creative/tweet_previews_spec.rb +41 -0
  59. data/spec/twitter-ads/rate_limit_spec.rb +247 -0
  60. data/spec/twitter-ads/retry_count_spec.rb +61 -0
  61. data/spec/twitter-ads/{creative/image_app_download_card_spec.rb → targeting/audience_summary_spec.rb} +16 -18
  62. metadata +50 -49
  63. data/lib/twitter-ads/audiences/audience_intelligence.rb +0 -68
  64. data/lib/twitter-ads/targeting/reach_estimate.rb +0 -78
  65. data/spec/fixtures/tweet_preview.json +0 -24
  66. data/spec/twitter-ads/campaign/reach_estimate_spec.rb +0 -103
  67. data/spec/twitter-ads/creative/account_media_spec.rb +0 -32
  68. data/spec/twitter-ads/creative/image_conversation_card_spec.rb +0 -40
  69. data/spec/twitter-ads/creative/video_app_download_card_spec.rb +0 -42
  70. data/spec/twitter-ads/creative/video_conversation_card_spec.rb +0 -51
  71. data/spec/twitter-ads/creative/website_card_spec.rb +0 -42
@@ -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
 
@@ -49,7 +48,7 @@ module TwitterAds
49
48
 
50
49
  # convert to `tweet_ids` param
51
50
  params = to_params
52
- params[:tweet_ids] = *params.delete(:tweet_id) if params.key?(:tweet_id)
51
+ params[:tweet_ids] = params.delete(:tweet_id) if params.key?(:tweet_id)
53
52
 
54
53
  if @id
55
54
  raise TwitterAds::NotFound.new(nil, 'Method PUT not allowed.', 404)
@@ -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(
@@ -9,13 +9,12 @@ module TwitterAds
9
9
  module Objective
10
10
  APP_ENGAGEMENTS = 'APP_ENGAGEMENTS'
11
11
  APP_INSTALLS = 'APP_INSTALLS'
12
+ ENGAGEMENTS = 'ENGAGEMENTS'
12
13
  FOLLOWERS = 'FOLLOWERS'
13
- LEAD_GENERATION = 'LEAD_GENERATION'
14
- TWEET_ENGAGEMENTS = 'TWEET_ENGAGEMENTS'
14
+ PREROLL_VIEWS = 'PREROLL_VIEWS'
15
+ REACH = 'REACH'
15
16
  VIDEO_VIEWS = 'VIDEO_VIEWS'
16
17
  WEBSITE_CLICKS = 'WEBSITE_CLICKS'
17
- WEBSITE_CONVERSIONS = 'WEBSITE_CONVERSIONS'
18
-
19
18
  end
20
19
 
21
20
  module Product
@@ -24,10 +23,15 @@ module TwitterAds
24
23
  end
25
24
 
26
25
  module Placement
27
- ALL_ON_TWITTER = 'ALL_ON_TWITTER'
28
- TWITTER_SEARCH = 'TWITTER_SEARCH'
29
- TWITTER_TIMELINE = 'TWITTER_TIMELINE'
30
- PUBLISHER_NETWORK = 'PUBLISHER_NETWORK'
26
+ ALL_ON_TWITTER = 'ALL_ON_TWITTER'
27
+ TWITTER_SEARCH = 'TWITTER_SEARCH'
28
+ TWITTER_TIMELINE = 'TWITTER_TIMELINE'
29
+ PUBLISHER_NETWORK = 'PUBLISHER_NETWORK'
30
+ TAP_FULL = 'TAP_FULL'
31
+ TAP_FULL_LANDSCAPE = 'TAP_FULL_LANDSCAPE'
32
+ TAP_BANNER = 'TAP_BANNER'
33
+ TAP_NATIVE = 'TAP_NATIVE'
34
+ TAP_MRECT = 'TAP_MRECT'
31
35
  end
32
36
 
33
37
  module Placement
@@ -106,6 +110,7 @@ module TwitterAds
106
110
  FUNDING_INSTRUMENT = 'FUNDING_INSTRUMENT'
107
111
  CAMPAIGN = 'CAMPAIGN'
108
112
  LINE_ITEM = 'LINE_ITEM'
113
+ PROMOTED_ACCOUNT = 'PROMOTED_ACCOUNT'
109
114
  PROMOTED_TWEET = 'PROMOTED_TWEET'
110
115
  ORGANIC_TWEET = 'ORGANIC_TWEET'
111
116
  MEDIA_CREATIVE = 'MEDIA_CREATIVE'
@@ -143,7 +148,10 @@ module TwitterAds
143
148
  end
144
149
 
145
150
  module Optimizations
151
+ APP_CLICKS = 'APP_CLICKS'
152
+ APP_INSTALLS = 'APP_INSTALLS'
146
153
  DEFAULT = 'DEFAULT'
154
+ ENGAGEMENTS = 'ENGAGEMENTS'
147
155
  WEBSITE_CONVERSIONS = 'WEBSITE_CONVERSIONS'
148
156
  end
149
157
 
@@ -218,11 +226,6 @@ module TwitterAds
218
226
  HASHTAG = 'HASHTAG'
219
227
  end
220
228
 
221
- module AudienceDefinition
222
- TARGETING_CRITERIA = 'TARGETING_CRITERIA'
223
- KEYWORD_AUDIENCE = 'KEYWORD_AUDIENCE'
224
- end
225
-
226
229
  module LookalikeExpansion
227
230
  DEFINED = 'DEFINED'
228
231
  EXPANDED = 'EXPANDED'
@@ -233,5 +236,11 @@ module TwitterAds
233
236
  PUBLISHED = 'PUBLISHED'
234
237
  SCHEDULED = 'SCHEDULED'
235
238
  end
239
+
240
+ module TimelineType
241
+ ALL = 'ALL'
242
+ NULLCAST = 'NULLCAST'
243
+ ORGANIC = 'ORGANIC'
244
+ end
236
245
  end
237
246
  end