twitter-ads 0.3.4
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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/CONTRIBUTING.md +77 -0
- data/LICENSE +22 -0
- data/README.md +111 -0
- data/Rakefile +86 -0
- data/bin/twitter-ads +42 -0
- data/lib/twitter-ads.rb +54 -0
- data/lib/twitter-ads/account.rb +229 -0
- data/lib/twitter-ads/audiences/tailored_audience.rb +177 -0
- data/lib/twitter-ads/campaign/app_list.rb +42 -0
- data/lib/twitter-ads/campaign/campaign.rb +40 -0
- data/lib/twitter-ads/campaign/funding_instrument.rb +33 -0
- data/lib/twitter-ads/campaign/line_item.rb +91 -0
- data/lib/twitter-ads/campaign/promotable_user.rb +28 -0
- data/lib/twitter-ads/campaign/targeting_criteria.rb +77 -0
- data/lib/twitter-ads/campaign/tweet.rb +83 -0
- data/lib/twitter-ads/client.rb +92 -0
- data/lib/twitter-ads/creative/app_download_card.rb +44 -0
- data/lib/twitter-ads/creative/image_app_download_card.rb +44 -0
- data/lib/twitter-ads/creative/image_conversation_card.rb +44 -0
- data/lib/twitter-ads/creative/lead_gen_card.rb +46 -0
- data/lib/twitter-ads/creative/promoted_account.rb +38 -0
- data/lib/twitter-ads/creative/promoted_tweet.rb +87 -0
- data/lib/twitter-ads/creative/video.rb +43 -0
- data/lib/twitter-ads/creative/video_app_download_card.rb +47 -0
- data/lib/twitter-ads/creative/video_conversation_card.rb +46 -0
- data/lib/twitter-ads/creative/website_card.rb +48 -0
- data/lib/twitter-ads/cursor.rb +127 -0
- data/lib/twitter-ads/enum.rb +135 -0
- data/lib/twitter-ads/error.rb +93 -0
- data/lib/twitter-ads/http/request.rb +127 -0
- data/lib/twitter-ads/http/response.rb +74 -0
- data/lib/twitter-ads/http/ton_upload.rb +140 -0
- data/lib/twitter-ads/legacy.rb +7 -0
- data/lib/twitter-ads/resources/analytics.rb +90 -0
- data/lib/twitter-ads/resources/dsl.rb +108 -0
- data/lib/twitter-ads/resources/persistence.rb +43 -0
- data/lib/twitter-ads/resources/resource.rb +92 -0
- data/lib/twitter-ads/targeting/reach_estimate.rb +69 -0
- data/lib/twitter-ads/utils.rb +76 -0
- data/lib/twitter-ads/version.rb +6 -0
- data/spec/fixtures/accounts_all.json +65 -0
- data/spec/fixtures/accounts_features.json +18 -0
- data/spec/fixtures/accounts_load.json +19 -0
- data/spec/fixtures/app_lists_all.json +22 -0
- data/spec/fixtures/app_lists_load.json +31 -0
- data/spec/fixtures/campaigns_all.json +208 -0
- data/spec/fixtures/campaigns_load.json +27 -0
- data/spec/fixtures/funding_instruments_all.json +74 -0
- data/spec/fixtures/funding_instruments_load.json +28 -0
- data/spec/fixtures/line_items_all.json +292 -0
- data/spec/fixtures/line_items_load.json +36 -0
- data/spec/fixtures/placements.json +35 -0
- data/spec/fixtures/promotable_users_all.json +57 -0
- data/spec/fixtures/promotable_users_load.json +18 -0
- data/spec/fixtures/promoted_tweets_all.json +212 -0
- data/spec/fixtures/promoted_tweets_load.json +19 -0
- data/spec/fixtures/reach_estimate.json +19 -0
- data/spec/fixtures/tailored_audiences_all.json +67 -0
- data/spec/fixtures/tailored_audiences_load.json +29 -0
- data/spec/fixtures/tweet_preview.json +24 -0
- data/spec/fixtures/videos_all.json +50 -0
- data/spec/fixtures/videos_load.json +22 -0
- data/spec/quality_spec.rb +15 -0
- data/spec/shared/properties.rb +20 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/helpers.rb +42 -0
- data/spec/twitter-ads/account_spec.rb +315 -0
- data/spec/twitter-ads/audiences/tailored_audience_spec.rb +45 -0
- data/spec/twitter-ads/campaign/app_list_spec.rb +108 -0
- data/spec/twitter-ads/campaign/line_item_spec.rb +95 -0
- data/spec/twitter-ads/campaign/reach_estimate_spec.rb +98 -0
- data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +39 -0
- data/spec/twitter-ads/campaign/tweet_spec.rb +83 -0
- data/spec/twitter-ads/client_spec.rb +115 -0
- data/spec/twitter-ads/creative/app_download_card_spec.rb +44 -0
- data/spec/twitter-ads/creative/image_app_download_card_spec.rb +43 -0
- data/spec/twitter-ads/creative/image_conversation_card_spec.rb +40 -0
- data/spec/twitter-ads/creative/lead_gen_card_spec.rb +46 -0
- data/spec/twitter-ads/creative/promoted_account_spec.rb +30 -0
- data/spec/twitter-ads/creative/promoted_tweet_spec.rb +46 -0
- data/spec/twitter-ads/creative/video_app_download_card_spec.rb +42 -0
- data/spec/twitter-ads/creative/video_conversation_card_spec.rb +52 -0
- data/spec/twitter-ads/creative/video_legacy_spec.rb +43 -0
- data/spec/twitter-ads/creative/video_spec.rb +43 -0
- data/spec/twitter-ads/creative/website_card_spec.rb +37 -0
- data/spec/twitter-ads/cursor_spec.rb +67 -0
- data/spec/twitter-ads/placements_spec.rb +36 -0
- data/spec/twitter-ads/utils_spec.rb +101 -0
- data/twitter-ads.gemspec +37 -0
- metadata +247 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
module Tweet
|
|
6
|
+
|
|
7
|
+
# cannot instaniate Tweet, only including class methods for stats
|
|
8
|
+
extend TwitterAds::Analytics::ClassMethods
|
|
9
|
+
|
|
10
|
+
RESOURCE_COLLECTION = '/0/accounts/%{account_id}/tweet/preview'.freeze # @api private
|
|
11
|
+
RESOURCE_STATS = '/0/stats/accounts/%{account_id}/organic_tweets'.freeze # @api private
|
|
12
|
+
RESOURCE = '/0/accounts/%{account_id}/tweet/preview/%{id}'.freeze # @api private
|
|
13
|
+
RESOURCE_CREATE = '/0/accounts/%{account_id}/tweet'.freeze # @api private
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
|
|
17
|
+
# Returns an HTML preview of a tweet, either new or existing
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# Tweet.preview(account, status: 'potatoes can be deadly...')
|
|
21
|
+
# Tweet.preview(account, id: 634798319504617472)
|
|
22
|
+
#
|
|
23
|
+
# @param client [Client] The Client object instance.
|
|
24
|
+
# @param account [Account] The Account object instance.
|
|
25
|
+
# @param opts [Hash] A hash of options.
|
|
26
|
+
#
|
|
27
|
+
# @option opts [Integer] :id The ID of an existing Tweet you want to preview.
|
|
28
|
+
# @option opts [String] :status The text of your status update, up to 140 characters.
|
|
29
|
+
# @option opts [Array] :media_ids A list of up to four media IDs to associate with the Tweet.
|
|
30
|
+
# @option opts [String] :card_id The base-36 ID of a revenue card to be embedded in the Tweet.
|
|
31
|
+
# @option opts [String] :preview_target The target to render the Tweet preview
|
|
32
|
+
# for (eg. TWITTER_TIMELINES).
|
|
33
|
+
#
|
|
34
|
+
# @return [Array] An array containing platforms & their respective tweet previews
|
|
35
|
+
#
|
|
36
|
+
# @since 0.2.0
|
|
37
|
+
# @see https://dev.twitter.com/ads/reference/get/accounts/%3Aaccount_id/tweet/preview
|
|
38
|
+
def preview(account, opts = {})
|
|
39
|
+
resource = opts.key?(:id) ? RESOURCE : RESOURCE_COLLECTION
|
|
40
|
+
resource = resource % { account_id: account.id, id: opts.delete(:id) }
|
|
41
|
+
|
|
42
|
+
# url encodes status message if present
|
|
43
|
+
opts[:status] = URI.escape(opts[:status]) if opts.key?(:status)
|
|
44
|
+
|
|
45
|
+
# handles array to string conversion for media IDs
|
|
46
|
+
if opts.key?(:media_ids) && opts[:media_ids].respond_to?(:join)
|
|
47
|
+
opts[:media_ids] = opts[:media_ids].join(',')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
response = TwitterAds::Request.new(account.client, :get, resource, params: opts).perform
|
|
51
|
+
response.body[:data]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Creates a "Promoted-Only" Tweet using the specialized Ads API end point.
|
|
55
|
+
#
|
|
56
|
+
# @param status [String] The main Tweet body (max: 140 characters).
|
|
57
|
+
# @param opts [Hash] A hash of options.
|
|
58
|
+
#
|
|
59
|
+
# @option opts [Array] :media_ids A list of up to four media IDs to associate with the Tweet.
|
|
60
|
+
# @option opts [Integer] :as_user_id The user ID whom you are posting the Tweet on behalf of.
|
|
61
|
+
# @option opts [Boolean] :trim_user Excludes the user object from the hydrated Tweet response.
|
|
62
|
+
# @option opts [String] :video_id The Video UUID to be associated with thie Tweet.
|
|
63
|
+
# @option opts [String] :video_title An optional title to be included.
|
|
64
|
+
# @option opts [String] :video_description An optional description to be included.
|
|
65
|
+
# @option opts [String] :video_cta An optional CTA value for the associated video.
|
|
66
|
+
# @option opts [String] :video_cta_value The value for the corresponding CTA.
|
|
67
|
+
#
|
|
68
|
+
# @since 0.3.0
|
|
69
|
+
#
|
|
70
|
+
# @see https://dev.twitter.com/ads/reference/post/accounts/%3Aaccount_id/tweet
|
|
71
|
+
#
|
|
72
|
+
# @return [Hash] A hash containing the newly created Tweet object.
|
|
73
|
+
def create(account, status, opts = {})
|
|
74
|
+
params = { status: status }.merge!(opts)
|
|
75
|
+
resource = RESOURCE_CREATE % { account_id: account.id }
|
|
76
|
+
response = TwitterAds::Request.new(account.client, :post, resource, params: params).perform
|
|
77
|
+
response.body[:data]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
|
|
6
|
+
# The Ads API Client class which functions as a
|
|
7
|
+
# container for basic API consumer information.
|
|
8
|
+
class Client
|
|
9
|
+
|
|
10
|
+
attr_accessor :consumer_key,
|
|
11
|
+
:consumer_secret,
|
|
12
|
+
:access_token,
|
|
13
|
+
:access_token_secret,
|
|
14
|
+
:options,
|
|
15
|
+
:logger
|
|
16
|
+
|
|
17
|
+
# Creates a new Ads API client instance.
|
|
18
|
+
#
|
|
19
|
+
# @param consumer_key nil [String] The application consumer key value.
|
|
20
|
+
# @param consumer_secret nil [String] The application consumer secret value.
|
|
21
|
+
# @param access_token nil [String] The access token value.
|
|
22
|
+
# @param access_token_secret nil [String] The access token secret value.
|
|
23
|
+
#
|
|
24
|
+
# @param opts [Hash] An optional Hash of extended options.
|
|
25
|
+
# @option opts [Boolean] :sandbox When true, enables sandbox mode for all requests.
|
|
26
|
+
# @option opts [Boolean] :trace When true, enables verbose request tracing for all requests.
|
|
27
|
+
#
|
|
28
|
+
# @since 0.1.0
|
|
29
|
+
#
|
|
30
|
+
# @return [Client] The newly created client instance.
|
|
31
|
+
def initialize(consumer_key, consumer_secret, access_token, access_token_secret, opts = {})
|
|
32
|
+
@consumer_key = consumer_key
|
|
33
|
+
@consumer_secret = consumer_secret
|
|
34
|
+
@access_token = access_token
|
|
35
|
+
@access_token_secret = access_token_secret
|
|
36
|
+
@options = opts
|
|
37
|
+
validate
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Returns the Logger instance for request logging.
|
|
42
|
+
#
|
|
43
|
+
# @since 0.2.0
|
|
44
|
+
#
|
|
45
|
+
# @return [Logger] The logger instance.
|
|
46
|
+
def logger
|
|
47
|
+
@logger ||= Logger.new(STDOUT)
|
|
48
|
+
@logger.progname = 'twitter-ads' unless @logger.progname
|
|
49
|
+
@logger
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns an inspection string for the current Client instance.
|
|
53
|
+
#
|
|
54
|
+
# @example
|
|
55
|
+
# client.inspect
|
|
56
|
+
#
|
|
57
|
+
# @since 0.1.0
|
|
58
|
+
#
|
|
59
|
+
# @return [String] The inspection string.
|
|
60
|
+
def inspect
|
|
61
|
+
"#<#{self.class.name}:0x#{object_id} consumer_key=\"#{@consumer_key}\">"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns a collection of advertiser Accounts available to the current access token.
|
|
65
|
+
#
|
|
66
|
+
# @example
|
|
67
|
+
# client.accounts
|
|
68
|
+
# client.accounts('3ofs6l')
|
|
69
|
+
# client.accounts('3ofs6l', with_deleted: true)
|
|
70
|
+
#
|
|
71
|
+
# @param id=nil [String] The account ID string.
|
|
72
|
+
# @param opts={} [Hash] Hash of optional values.
|
|
73
|
+
#
|
|
74
|
+
# @option opts [String] :with_deleted Indicates whether or not to included deleted objects.
|
|
75
|
+
#
|
|
76
|
+
# @since 0.1.0
|
|
77
|
+
#
|
|
78
|
+
# @return [Account] The instance of the Account object.
|
|
79
|
+
def accounts(id = nil, opts = {})
|
|
80
|
+
id ? Account.load(self, id) : Account.all(self, opts)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def validate
|
|
86
|
+
[:consumer_key, :consumer_secret, :access_token, :access_token_secret].each do |name|
|
|
87
|
+
fail(ArgumentError, "Error! Missing required #{name}.") unless send(name)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
module Creative
|
|
6
|
+
|
|
7
|
+
class AppDownloadCard
|
|
8
|
+
|
|
9
|
+
include TwitterAds::DSL
|
|
10
|
+
include TwitterAds::Resource
|
|
11
|
+
include TwitterAds::Persistence
|
|
12
|
+
|
|
13
|
+
attr_reader :account
|
|
14
|
+
|
|
15
|
+
property :id, read_only: true
|
|
16
|
+
property :preview_url, read_only: true
|
|
17
|
+
property :deleted, type: :bool, read_only: true
|
|
18
|
+
property :created_at, type: :time, read_only: true
|
|
19
|
+
property :updated_at, type: :time, read_only: true
|
|
20
|
+
|
|
21
|
+
property :name
|
|
22
|
+
property :app_country_code
|
|
23
|
+
property :iphone_app_id
|
|
24
|
+
property :iphone_deep_link
|
|
25
|
+
property :ipad_app_id
|
|
26
|
+
property :ipad_deep_link
|
|
27
|
+
property :googleplay_app_id
|
|
28
|
+
property :googleplay_deep_link
|
|
29
|
+
property :app_cta
|
|
30
|
+
property :custom_icon_media_id
|
|
31
|
+
property :custom_app_description
|
|
32
|
+
|
|
33
|
+
RESOURCE_COLLECTION = '/0/accounts/%{account_id}/cards/app_download'.freeze # @api private
|
|
34
|
+
RESOURCE = '/0/accounts/%{account_id}/cards/app_download/%{id}'.freeze # @api private
|
|
35
|
+
|
|
36
|
+
def initialize(account)
|
|
37
|
+
@account = account
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
module Creative
|
|
6
|
+
|
|
7
|
+
class ImageAppDownloadCard
|
|
8
|
+
|
|
9
|
+
include TwitterAds::DSL
|
|
10
|
+
include TwitterAds::Resource
|
|
11
|
+
include TwitterAds::Persistence
|
|
12
|
+
|
|
13
|
+
attr_reader :account
|
|
14
|
+
|
|
15
|
+
property :id, read_only: true
|
|
16
|
+
property :preview_url, read_only: true
|
|
17
|
+
property :deleted, type: :bool, read_only: true
|
|
18
|
+
property :created_at, type: :time, read_only: true
|
|
19
|
+
property :updated_at, type: :time, read_only: true
|
|
20
|
+
|
|
21
|
+
property :name
|
|
22
|
+
property :app_country_code
|
|
23
|
+
property :iphone_app_id
|
|
24
|
+
property :iphone_deep_link
|
|
25
|
+
property :ipad_app_id
|
|
26
|
+
property :ipad_deep_link
|
|
27
|
+
property :googleplay_app_id
|
|
28
|
+
property :googleplay_deep_link
|
|
29
|
+
property :app_cta
|
|
30
|
+
property :wide_app_image_media_id
|
|
31
|
+
|
|
32
|
+
RESOURCE_COLLECTION =
|
|
33
|
+
'/0/accounts/%{account_id}/cards/image_app_download'.freeze # @api private
|
|
34
|
+
RESOURCE = '/0/accounts/%{account_id}/cards/image_app_download/%{id}'.freeze # @api private
|
|
35
|
+
|
|
36
|
+
def initialize(account)
|
|
37
|
+
@account = account
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
module Creative
|
|
6
|
+
|
|
7
|
+
class ImageConversationCard
|
|
8
|
+
|
|
9
|
+
include TwitterAds::DSL
|
|
10
|
+
include TwitterAds::Resource
|
|
11
|
+
include TwitterAds::Persistence
|
|
12
|
+
|
|
13
|
+
attr_reader :account
|
|
14
|
+
|
|
15
|
+
property :id, read_only: true
|
|
16
|
+
property :preview_url, read_only: true
|
|
17
|
+
property :image, read_only: true
|
|
18
|
+
property :deleted, type: :bool, read_only: true
|
|
19
|
+
property :created_at, type: :time, read_only: true
|
|
20
|
+
property :updated_at, type: :time, read_only: true
|
|
21
|
+
|
|
22
|
+
property :name
|
|
23
|
+
property :title
|
|
24
|
+
property :first_cta
|
|
25
|
+
property :first_cta_tweet
|
|
26
|
+
property :second_cta
|
|
27
|
+
property :second_cta_tweet
|
|
28
|
+
property :thank_you_text
|
|
29
|
+
property :thank_you_url
|
|
30
|
+
property :image_media_id
|
|
31
|
+
|
|
32
|
+
RESOURCE_COLLECTION =
|
|
33
|
+
'/0/accounts/%{account_id}/cards/image_conversation'.freeze # @api private
|
|
34
|
+
RESOURCE = '/0/accounts/%{account_id}/cards/image_conversation/%{id}'.freeze # @api private
|
|
35
|
+
|
|
36
|
+
def initialize(account)
|
|
37
|
+
@account = account
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
module Creative
|
|
6
|
+
|
|
7
|
+
class LeadGenCard
|
|
8
|
+
|
|
9
|
+
include TwitterAds::DSL
|
|
10
|
+
include TwitterAds::Resource
|
|
11
|
+
include TwitterAds::Persistence
|
|
12
|
+
|
|
13
|
+
attr_reader :account
|
|
14
|
+
|
|
15
|
+
property :id, read_only: true
|
|
16
|
+
property :preview_url, read_only: true
|
|
17
|
+
property :deleted, type: :bool, read_only: true
|
|
18
|
+
property :created_at, type: :time, read_only: true
|
|
19
|
+
property :updated_at, type: :time, read_only: true
|
|
20
|
+
|
|
21
|
+
property :name
|
|
22
|
+
property :image_media_id
|
|
23
|
+
property :cta
|
|
24
|
+
property :fallback_url
|
|
25
|
+
property :privacy_policy_url
|
|
26
|
+
property :title
|
|
27
|
+
property :submit_url
|
|
28
|
+
property :submit_method
|
|
29
|
+
property :custom_destination_url
|
|
30
|
+
property :custom_destination_text
|
|
31
|
+
property :custom_key_screen_name
|
|
32
|
+
property :custom_key_name
|
|
33
|
+
property :custom_key_email
|
|
34
|
+
|
|
35
|
+
RESOURCE_COLLECTION = '/0/accounts/%{account_id}/cards/lead_gen'.freeze # @api private
|
|
36
|
+
RESOURCE = '/0/accounts/%{account_id}/cards/lead_gen/%{id}'.freeze # @api private
|
|
37
|
+
|
|
38
|
+
def initialize(account)
|
|
39
|
+
@account = account
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
module Creative
|
|
6
|
+
|
|
7
|
+
class PromotedAccount
|
|
8
|
+
|
|
9
|
+
include TwitterAds::DSL
|
|
10
|
+
include TwitterAds::Resource
|
|
11
|
+
include TwitterAds::Persistence
|
|
12
|
+
include TwitterAds::Analytics
|
|
13
|
+
|
|
14
|
+
attr_reader :account
|
|
15
|
+
|
|
16
|
+
property :id, read_only: true
|
|
17
|
+
property :approval_status, read_only: true
|
|
18
|
+
property :created_at, type: :time, read_only: true
|
|
19
|
+
property :updated_at, type: :time, read_only: true
|
|
20
|
+
property :deleted, type: :bool, read_only: true
|
|
21
|
+
|
|
22
|
+
property :line_item_id
|
|
23
|
+
property :user_id
|
|
24
|
+
property :paused, type: :bool
|
|
25
|
+
|
|
26
|
+
RESOURCE_COLLECTION = '/0/accounts/%{account_id}/promoted_accounts'.freeze # @api private
|
|
27
|
+
RESOURCE_STATS = '/0/stats/accounts/%{account_id}/promoted_accounts'.freeze # @api private
|
|
28
|
+
RESOURCE = '/0/accounts/%{account_id}/promoted_accounts/%{id}'.freeze # @api private
|
|
29
|
+
|
|
30
|
+
def initialize(account)
|
|
31
|
+
@account = account
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
module TwitterAds
|
|
5
|
+
module Creative
|
|
6
|
+
|
|
7
|
+
class PromotedTweet
|
|
8
|
+
|
|
9
|
+
include TwitterAds::DSL
|
|
10
|
+
include TwitterAds::Resource
|
|
11
|
+
include TwitterAds::Persistence
|
|
12
|
+
include TwitterAds::Analytics
|
|
13
|
+
|
|
14
|
+
attr_reader :account
|
|
15
|
+
|
|
16
|
+
property :id, read_only: true
|
|
17
|
+
property :approval_status, read_only: true
|
|
18
|
+
property :created_at, type: :time, read_only: true
|
|
19
|
+
property :updated_at, type: :time, read_only: true
|
|
20
|
+
property :deleted, type: :bool, read_only: true
|
|
21
|
+
|
|
22
|
+
property :line_item_id
|
|
23
|
+
property :tweet_id
|
|
24
|
+
property :paused, type: :bool
|
|
25
|
+
|
|
26
|
+
RESOURCE_COLLECTION = '/0/accounts/%{account_id}/promoted_tweets'.freeze # @api private
|
|
27
|
+
RESOURCE_STATS = '/0/stats/accounts/%{account_id}/promoted_tweets'.freeze # @api private
|
|
28
|
+
RESOURCE = '/0/accounts/%{account_id}/promoted_tweets/%{id}'.freeze # @api private
|
|
29
|
+
|
|
30
|
+
def initialize(account)
|
|
31
|
+
@account = account
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Saves or updates the current object instance depending on the presence of `object.id`.
|
|
36
|
+
#
|
|
37
|
+
# @example
|
|
38
|
+
# object.save
|
|
39
|
+
#
|
|
40
|
+
# @return [self] Returns the instance refreshed from the API.
|
|
41
|
+
#
|
|
42
|
+
# Note: override to handle the inconsistency of the promoted tweet endpoint. (see REVAPI-5348)
|
|
43
|
+
#
|
|
44
|
+
# @since 0.2.4
|
|
45
|
+
def save
|
|
46
|
+
# manually check for missing params (due to API discrepancy)
|
|
47
|
+
validate
|
|
48
|
+
|
|
49
|
+
# convert to `tweet_ids` param
|
|
50
|
+
params = to_params
|
|
51
|
+
params[:tweet_ids] = *params.delete(:tweet_id) if params.key?(:tweet_id)
|
|
52
|
+
|
|
53
|
+
if @id
|
|
54
|
+
resource = self.class::RESOURCE % { account_id: account.id, id: id }
|
|
55
|
+
response = Request.new(account.client, :put, resource, params: params).perform
|
|
56
|
+
from_response(response.body[:data])
|
|
57
|
+
else
|
|
58
|
+
resource = self.class::RESOURCE_COLLECTION % { account_id: account.id }
|
|
59
|
+
response = Request.new(account.client, :post, resource, params: params).perform
|
|
60
|
+
from_response(response.body[:data].first)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def validate
|
|
67
|
+
details = []
|
|
68
|
+
|
|
69
|
+
unless @line_item_id
|
|
70
|
+
details << { code: 'MISSING_PARAMETER',
|
|
71
|
+
message: '"line_item_id" is a required parameter',
|
|
72
|
+
parameter: 'line_item_id' }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
unless @tweet_id
|
|
76
|
+
details << { code: 'MISSING_PARAMETER',
|
|
77
|
+
message: '"tweet_id" is a required parameter',
|
|
78
|
+
parameter: 'tweet_id' }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
raise TwitterAds::ClientError.new(nil, details, 400) unless details.empty?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|