diff --git a/examples/promoted_tweet.py b/examples/promoted_tweet.py index ec29806..b40d103 100644 --- a/examples/promoted_tweet.py +++ b/examples/promoted_tweet.py @@ -8,32 +8,32 @@ CONSUMER_SECRET = 'your consumer secret' ACCESS_TOKEN = 'user access token' ACCESS_TOKEN_SECRET = 'user access token secret' -ADS_ACCOUNT = 'ads account id' +ACCOUNT_ID = 'ads account id' # initialize the twitter ads api client client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET) # load up the account instance, campaign and line item -account = client.accounts(ADS_ACCOUNT) +account = client.accounts(ACCOUNT_ID) campaign = account.campaigns().next() line_item = account.line_items(None, campaign_ids=campaign.id).next() # create request for a simple nullcasted tweet tweet1 = Tweet.create(account, text='There can be only one...') -# promote the tweet using our line item -promoted_tweet = PromotedTweet(account) -promoted_tweet.line_item_id = line_item.id -promoted_tweet.tweet_id = tweet1['id'] -promoted_tweet.save() - # create request for a nullcasted tweet with a website card website_card = WebsiteCard.all(account).next() -text = "Fine. There can be two. {card_url}".format(card_url=website_card.preview_url) -tweet2 = Tweet.create(account, text) +tweet2 = Tweet.create(account, text='Fine. There can be two.', card_uri=website_card.card_uri) # promote the tweet using our line item -promoted_tweet = PromotedTweet(account) -promoted_tweet.line_item_id = line_item.id -promoted_tweet.tweet_id = tweet2['id'] -promoted_tweet.save() +tweet_ids = [tweet1['id'], tweet2['id']] + +response = PromotedTweet.attach( + account, + line_item_id=line_item.id, + tweet_ids=tweet_ids +) + +for i in response: + print(i.id) + print(i.tweet_id) diff --git a/tests/fixtures/promoted_tweets_attach.json b/tests/fixtures/promoted_tweets_attach.json new file mode 100644 index 0000000..29f7101 --- /dev/null +++ b/tests/fixtures/promoted_tweets_attach.json @@ -0,0 +1,25 @@ +{ + "data_type": "promoted_tweet", + "data": [ + { + "line_item_id": "2b7xw", + "id": "6thl4", + "entity_status": "ACTIVE", + "created_at": "2015-04-11T20:50:25Z", + "updated_at": "2015-04-11T20:50:25Z", + "approval_status": "ACCEPTED", + "tweet_id": "585127452231467008", + "deleted": false + } + ], + "request": { + "params": { + "line_item_id": "2b7xw", + "tweet_ids": [ + 585127452231467008 + ], + "account_id": "2iqph" + } + }, + "total_count": 1 +} diff --git a/tests/test_promoted_tweets.py b/tests/test_promoted_tweets.py index 929d429..04e2ee6 100644 --- a/tests/test_promoted_tweets.py +++ b/tests/test_promoted_tweets.py @@ -65,3 +65,34 @@ def test_promoted_tweets_load(): promoted_tweet = PromotedTweet.load(account, '6thl4') assert promoted_tweet.id == '6thl4' assert promoted_tweet.entity_status == 'ACTIVE' + + +@responses.activate +def test_promoted_tweets_attach(): + responses.add(responses.GET, + with_resource('/' + API_VERSION + '/accounts/2iqph'), + body=with_fixture('accounts_load'), + content_type='application/json') + + responses.add(responses.POST, + with_resource('/' + API_VERSION + '/accounts/2iqph/promoted_tweets'), + body=with_fixture('promoted_tweets_attach'), + content_type='application/json') + + client = Client( + characters(40), + characters(40), + characters(40), + characters(40) + ) + + account = Account.load(client, '2iqph') + response = PromotedTweet.attach( + account, + line_item_id='2b7xw', + tweet_ids=['585127452231467008'] + ) + + assert isinstance(response, Cursor) + assert response.count == 1 + assert response.first.id == '6thl4' diff --git a/twitter_ads/creative.py b/twitter_ads/creative.py index 675f159..70d0354 100644 --- a/twitter_ads/creative.py +++ b/twitter_ads/creative.py @@ -3,7 +3,6 @@ """Container for all creative management logic used by the Ads API SDK.""" from requests.exceptions import HTTPError - from twitter_ads import API_VERSION from twitter_ads.cursor import Cursor from twitter_ads.enum import TRANSFORM @@ -40,6 +39,9 @@ class PromotedTweet(Analytics, Resource, Persistence): RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts/{account_id}/promoted_tweets' RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/promoted_tweets/{id}' + @Deprecated('This method has been deprecated and will no longer be available ' + 'in the next major version update. Please use PromotedTweet.attach() ' + 'method instead.') def save(self): """ Saves or updates the current object instance depending on the @@ -57,6 +59,19 @@ def save(self): response = Request(self.account.client, 'post', resource, params=params).perform() return self.from_response(response.body['data'][0]) + @classmethod + def attach(klass, account, line_item_id=None, tweet_ids=None): + """ + Associate one or more Tweets with the specified line item. + """ + params = {} + params['line_item_id'] = line_item_id + params['tweet_ids'] = ",".join(map(str, tweet_ids)) + + resource = klass.RESOURCE_COLLECTION.format(account_id=account.id) + request = Request(account.client, 'post', resource, params=params) + return Cursor(klass, request, init_with=[account]) + # promoted tweet properties # read-only @@ -66,9 +81,8 @@ def save(self): resource_property(PromotedTweet, 'entity_status', readonly=True) resource_property(PromotedTweet, 'id', readonly=True) resource_property(PromotedTweet, 'updated_at', readonly=True, transform=TRANSFORM.TIME) -# writable +resource_property(PromotedTweet, 'tweet_id') resource_property(PromotedTweet, 'line_item_id') -resource_property(PromotedTweet, 'tweet_id') # SDK limitation class AccountMedia(Resource, Persistence):