def new(request): """ Returns a new campaign """ client = Client(settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") campaign_name = request.GET.get("campaign", "") daily_budget = request.GET.get("daily_budget", "") account = client.accounts(account_id) # create your campaign json_data = {} try: campaign = Campaign(account) campaign.funding_instrument_id = account.funding_instruments().next( ).id campaign.daily_budget_amount_local_micro = int(daily_budget) * 1000 campaign.name = campaign_name campaign.paused = True campaign.start_time = datetime.datetime.utcnow() campaign.save() json_data = { "valid": True, "account_id": account_id, "campaign_name": campaign_name, "campaign_id": campaign.id } except Error as e: json_data["response"] = e.details json_data["valid"] = False # passing as we send the json_data pass return HttpResponse(json.dumps(json_data), content_type="application/json")
def pushEmails2Twitter(hashedEmails,twCred): from twitter_ads.client import Client from twitter_ads.audience import TailoredAudience from twitter_ads.enum import TA_LIST_TYPES, TA_OPERATIONS CONSUMER_KEY = 'your consumer key' CONSUMER_SECRET = 'your consumer secret' ACCESS_TOKEN = 'access token' ACCESS_TOKEN_SECRET = 'access token secret' ACCOUNT_ID = 'account id' # initialize the client client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET) # load the advertiser account instance account = client.accounts(ACCOUNT_ID) # create a new tailored audience audience = TailoredAudience.create(account, '/path/to/file', 'my list', TA_LIST_TYPES.EMAIL) # check the processing status audience.status() # update the tailored audience audience.update('/path/to/file', TA_LIST_TYPES.TWITTER_ID, TA_OPERATIONS.REMOVE) audience.update('/path/to/file', TA_LIST_TYPES.PHONE_NUMBER, TA_OPERATIONS.ADD) # delete the tailored audience audience.delete() # add users to the account's global opt-out list TailoredAudience.opt_out(account, '/path/to/file', TA_OPERATIONS.HANDLE)
def new(request): """ Returns a new campaign """ client = Client( settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") campaign_name = request.GET.get("campaign", "") daily_budget = request.GET.get("daily_budget", "") account = client.accounts(account_id) # create your campaign json_data = {} try: campaign = Campaign(account) campaign.funding_instrument_id = account.funding_instruments().next().id campaign.daily_budget_amount_local_micro = int(daily_budget) * 1000 campaign.name = campaign_name campaign.paused = True campaign.start_time = datetime.datetime.utcnow() campaign.save() json_data = { "valid": True, "account_id": account_id, "campaign_name": campaign_name, "campaign_id": campaign.id} except Error as e: json_data["response"] = e.details json_data["valid"] = False # passing as we send the json_data pass return HttpResponse(json.dumps(json_data), content_type="application/json")
def json_handler(request): """ Returns json_data {"campaigns": [campaign_list} for given request """ client = Client(settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") campaign_id = request.GET.get("campaign_id", "") account = client.accounts(account_id) # TODO: Link to Ads API Docs for LineItem.rst line_items = account.line_items(None, campaign_ids=campaign_id) line_item_list = [] for line_item in line_items: name = line_item.name identifier = line_item.id objective = line_item.objective bid_amount = line_item.bid_amount_local_micro # Sometimes Bid Amount is None if bid_amount is not None: bid_amount = bid_amount / 10000 line_item_list.append({ "name": name, "id": identifier, "objective": objective, "bid_amount": bid_amount }) return HttpResponse(json.dumps({ "account_id": account_id, "campaign_id": campaign_id, "line_items": line_item_list }), content_type="application/json")
def new_targeting(request): """ Creates a new """ line_item_id = request.GET.get("line_item_id", "") account_id = request.GET.get("account_id", "") targeting_value = request.GET.get("targeting_value") targeting_type = "BEHAVIOR_EXPANDED" json_data = {} try: client = Client(settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account = client.accounts(account_id) targeting_criteria = TargetingCriteria(account) targeting_criteria.line_item_id = line_item_id targeting_criteria.targeting_type = targeting_type targeting_criteria.targeting_value = targeting_value if targeting_value == "TAILORED_AUDIENCE": targeting_criteria.tailored_audience_type = "FLEXIBLE" targeting_criteria.save() json_data = { "valid": True, "account_id": account_id, "line_item_id": line_item_id, "targeting_value": targeting_value } except Error as e: json_data["response"] = e.details json_data["valid"] = False # passing to push the json_data to the browser pass return HttpResponse(json.dumps(json_data), content_type="application/json")
def json_handler(request): """ Returns json_data {"campaigns": [campaign_list} for given request """ client = Client( settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") campaign_id = request.GET.get("campaign_id", "") account = client.accounts(account_id) # TODO: Link to Ads API Docs for LineItem.rst line_items = account.line_items(None, campaign_ids=campaign_id) line_item_list = [] for line_item in line_items: name = line_item.name identifier = line_item.id objective = line_item.objective bid_amount = line_item.bid_amount_local_micro # Sometimes Bid Amount is None if bid_amount is not None: bid_amount = bid_amount / 10000 line_item_list.append({"name": name, "id": identifier, "objective": objective, "bid_amount": bid_amount}) return HttpResponse( json.dumps( { "account_id": account_id, "campaign_id": campaign_id, "line_items": line_item_list}), content_type="application/json")
def new_targeting(request): """ Creates a new """ line_item_id = request.GET.get("line_item_id", "") account_id = request.GET.get("account_id", "") targeting_value = request.GET.get("targeting_value") targeting_type = "BEHAVIOR_EXPANDED" json_data = {} try: client = Client( settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account = client.accounts(account_id) targeting_criteria = TargetingCriteria(account) targeting_criteria.line_item_id = line_item_id targeting_criteria.targeting_type = targeting_type targeting_criteria.targeting_value = targeting_value if targeting_value == "TAILORED_AUDIENCE": targeting_criteria.tailored_audience_type = "FLEXIBLE" targeting_criteria.save() json_data = { "valid": True, "account_id": account_id, "line_item_id": line_item_id, "targeting_value": targeting_value} except Error as e: json_data["response"] = e.details json_data["valid"] = False # passing to push the json_data to the browser pass return HttpResponse(json.dumps(json_data), content_type="application/json")
def test_accounts_with_no_id(): responses.add(responses.GET, with_resource('/1/accounts'), body=with_fixture('accounts_all'), content_type='application/json') client = Client(characters(40), characters(40), characters(40), characters(40)) cursor = client.accounts() assert cursor is not None assert isinstance(cursor, Cursor) assert cursor.count == 5
def test_accounts_with_id(): responses.add(responses.GET, with_resource('/1/accounts/2iqph'), body=with_fixture('accounts_load'), content_type='application/json') client = Client(characters(40), characters(40), characters(40), characters(40)) account = client.accounts('2iqph') assert account is not None assert isinstance(account, Account) assert account.id == '2iqph'
def fetch_accounts(self, data, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET): res = {} account_id = data.get('account_id') if isinstance(account_id,(int,long)): account_id = int_to_base36(account_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id) resource = '/{api_version}/accounts/{account_id}'.format(api_version=settings.TW_API_VERSION, account_id=account_id) response = Request(client, 'get', resource).perform() if response.headers['x-rate-limit-remaining'] == "0" and settings.TW_RATE_LIMIT_ALERT: send_twitter_alert_email({"account_id": account_id, "endpoint": resource}) res['data'] = response.body['data'] res['success'] = True except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = { 'data': {}, 'success': False, 'message': str(e) } return res
def get(self, request): q = request.query_params.get('q') tw_user_id = request.query_params.get('tw_user_id') tw_user = TwitterUser.objects_raw.get(pk=tw_user_id) client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, tw_user.oauth_token, tw_user.oauth_secret) accounts = client.accounts() results = [] for a in accounts: tw_account = TwitterAccount.objects_raw.filter( tw_account_id=int(a.id, 36)).first() if not tw_account and (not q or (q and (q in a.name or q in a.id))): results.append(dict(name=a.name, id=a.id)) return Response(dict(results=results))
def test_accounts_with_no_id(): responses.add(responses.GET, with_resource('/' + API_VERSION + '/accounts'), body=with_fixture('accounts_all'), content_type='application/json') client = Client( characters(40), characters(40), characters(40), characters(40) ) cursor = client.accounts() assert cursor is not None assert isinstance(cursor, Cursor) assert cursor.count == 5
def test_accounts_with_id(): responses.add(responses.GET, with_resource('/' + API_VERSION + '/accounts/2iqph'), body=with_fixture('accounts_load'), content_type='application/json') client = Client( characters(40), characters(40), characters(40), characters(40) ) account = client.accounts('2iqph') assert account is not None assert isinstance(account, Account) assert account.id == '2iqph'
def json_handler(request): """ Returns json_data {"accounts": [account_list]} for given request """ client = Client(settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) accounts = client.accounts() # TODO: Link to Ads API Docs for Account.request account_list = [] for account in accounts: name = account.name identifier = account.id account_list.append({"name": name, "id": identifier}) return HttpResponse(json.dumps({"accounts": account_list}), content_type="application/json")
def json_handler(request): """ Returns json_data {"accounts": [account_list]} for given request """ client = Client( settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) accounts = client.accounts() # TODO: Link to Ads API Docs for Account.request account_list = [] for account in accounts: name = account.name identifier = account.id account_list.append({"name": name, "id": identifier}) return HttpResponse(json.dumps( {"accounts": account_list}), content_type="application/json")
def json_handler(request): """ Returns json_data {"campaigns": [campaign_list} for given request """ client = Client( settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") account = client.accounts(account_id) # TODO: Link to Ads API Docs for Campaign.rst campaigns = account.campaigns() campaign_list = [] for campaign in campaigns: name = campaign.name identifier = campaign.id campaign_list.append({"name": name, "id": identifier}) return HttpResponse(json.dumps( {"account_id": account_id, "campaigns": campaign_list}), content_type="application/json")
def new(request): """ Returns a new line item """ client = Client(settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") campaign_id = request.GET.get("campaign_id", "") campaign_name = request.GET.get("name", "") budget = request.GET.get("budget", "") account_id = request.GET.get("account_id", "") name = request.GET.get("name", "") bid_amount = request.GET.get("bid_amount", "") json_data = {} try: account = client.accounts(account_id) # create your campaign line_item = LineItem(account) line_item.campaign_id = campaign_id line_item.name = name line_item.product_type = PRODUCT.PROMOTED_TWEETS line_item.placements = [PLACEMENT.ALL_ON_TWITTER] line_item.objective = OBJECTIVE.TWEET_ENGAGEMENTS line_item.bid_amount_local_micro = int(bid_amount) * 1000 line_item.paused = True line_item.save() json_data = { "account_id": account_id, "campaign_name": campaign_name, "campaign_id": campaign_id } except Error as e: json_data["response"] = e.details json_data["valid"] = False pass return HttpResponse(json.dumps(json_data), content_type="application/json")
def new(request): """ Returns a new line item """ client = Client( settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") campaign_id = request.GET.get("campaign_id", "") campaign_name = request.GET.get("name", "") budget = request.GET.get("budget", "") account_id = request.GET.get("account_id", "") name = request.GET.get("name", "") bid_amount = request.GET.get("bid_amount", "") json_data = {} try: account = client.accounts(account_id) # create your campaign line_item = LineItem(account) line_item.campaign_id = campaign_id line_item.name = name line_item.product_type = PRODUCT.PROMOTED_TWEETS line_item.placements = [PLACEMENT.ALL_ON_TWITTER] line_item.objective = OBJECTIVE.TWEET_ENGAGEMENTS line_item.bid_amount_local_micro = int(bid_amount) * 1000 line_item.paused = True line_item.save() json_data = { "account_id": account_id, "campaign_name": campaign_name, "campaign_id": campaign_id} except Error as e: json_data["response"] = e.details json_data["valid"] = False pass return HttpResponse(json.dumps(json_data), content_type="application/json")
def post(self, request): tw_user_id = request.data.get('tw_user_id') tw_user = TwitterUser.objects_raw.get(pk=tw_user_id) tw_account_id = request.data.get('tw_account_id') advertiser_id = request.data.get('advertiser_id') advertiser = Advertiser.objects_raw.get(pk=advertiser_id) client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, tw_user.oauth_token, tw_user.oauth_secret) account = client.accounts(tw_account_id) users = account.promotable_users() user_info = None is_manage = False for u in users: if u.promotable_user_type == 'FULL': api = twitter.Api(consumer_key=settings.TW_CONSUMER_KEY, consumer_secret=settings.TW_CONSUMER_SECRET, access_token_key=tw_user.oauth_token, access_token_secret=tw_user.oauth_secret) # https://dev.twitter.com/rest/reference/get/users/show # https://api.twitter.com/1.1/users/show.json?screen_name=<user_id> user_info = api.GetUser(user_id=u.user_id) funding_instruments = account.funding_instruments() for f in funding_instruments: if not f.cancelled and f.id in settings.TW_MANAGE_FUNDING_INSTRUMENT_IDS: is_manage = True if user_info: tw_promotable_user, created = TwitterUser.objects_raw.get_or_create( tw_twitter_user_id=user_info.id, name=user_info.screen_name) TwitterAccount(tw_account_id=int(tw_account_id, 36), promotable_user_id=tw_promotable_user, name=account.name, advertiser_id=advertiser, tw_twitter_user_id=tw_user, is_manage=is_manage).save() return Response({'status': 'ok'})
def json_handler(request): """ Returns json_data {"campaigns": [campaign_list} for given request """ client = Client(settings.SOCIAL_AUTH_TWITTER_KEY, settings.SOCIAL_AUTH_TWITTER_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_TOKEN_SECRET) account_id = request.GET.get("account_id", "") account = client.accounts(account_id) # TODO: Link to Ads API Docs for Campaign.rst campaigns = account.campaigns() campaign_list = [] for campaign in campaigns: name = campaign.name identifier = campaign.id campaign_list.append({"name": name, "id": identifier}) return HttpResponse(json.dumps({ "account_id": account_id, "campaigns": campaign_list }), content_type="application/json")
class TwitterReader(Reader): def __init__( self, consumer_key, consumer_secret, access_token, access_token_secret, account_id, report_type, entity, entity_attribute, granularity, metric_group, placement, segmentation_type, platform, country, start_date, end_date, add_request_date_to_report, date_range, ): # Authentication inputs self.client = Client(consumer_key, consumer_secret, access_token, access_token_secret) self.account = self.client.accounts(account_id) # General inputs self.report_type = report_type self.entity = entity self.start_date, self.end_date = build_date_range( start_date, end_date, date_range) self.end_date = self.end_date + timedelta(days=1) self.add_request_date_to_report = add_request_date_to_report # Report inputs: ENTITY self.entity_attributes = list(entity_attribute) # Report inputs: ANALYTICS self.granularity = granularity self.metric_groups = list(metric_group) self.placement = placement self.segmentation_type = segmentation_type self.platform = platform self.country = country # Validate inputs self.validate_inputs() def validate_inputs(self): """ Validate combination of input parameters (triggered in TwitterReader constructor). """ self.validate_analytics_segmentation() self.validate_analytics_metric_groups() self.validate_analytics_entity() self.validate_reach_entity() self.validate_entity_attributes() def validate_analytics_segmentation(self): if self.report_type == "ANALYTICS": if self.segmentation_type in ["DEVICES", "PLATFORM VERSION" ] and not self.platform: raise ClickException("Please provide a value for 'platform'.") elif self.segmentation_type in [ "CITIES", "POSTAL_CODES", "REGION" ] and not self.country: raise ClickException("Please provide a value for 'country'.") def validate_analytics_metric_groups(self): if self.report_type == "ANALYTICS": if self.entity == "FUNDING_INSTRUMENT" and any([ metric_group not in ["ENGAGEMENT", "BILLING"] for metric_group in self.metric_groups ]): raise ClickException( "'FUNDING_INSTRUMENT' only accept the 'ENGAGEMENT' and 'BILLING' metric groups." ) if "MOBILE_CONVERSION" in self.metric_groups and len( self.metric_groups) > 1: raise ClickException( "'MOBILE_CONVERSION' data should be requested separately.") def validate_analytics_entity(self): if self.report_type == "ANALYTICS": if self.entity == "CARD": raise ClickException( f"'ANALYTICS' reports only accept following entities: {list(ENTITY_OBJECTS.keys())}." ) def validate_reach_entity(self): if self.report_type == "REACH": if self.entity not in ["CAMPAIGN", "FUNDING_INSTRUMENT"]: raise ClickException( "'REACH' reports only accept the following entities: CAMPAIGN, FUNDING_INSTRUMENT." ) def validate_entity_attributes(self): if self.report_type == "ENTITY": if not all([ attr in ENTITY_ATTRIBUTES[self.entity] for attr in self.entity_attributes ]): raise ClickException( f"Available attributes for '{self.entity}' are: {ENTITY_ATTRIBUTES[self.entity]}" ) def get_analytics_report(self, job_ids): """ Get 'ANALYTICS' report through the 'Asynchronous Analytics' endpoint of Twitter Ads API. Documentation: https://developer.twitter.com/en/docs/ads/analytics/api-reference/asynchronous """ all_responses = [] for job_id in job_ids: logger.info(f"Processing job_id: {job_id}") # job_result = self.get_job_result(job_id) # waiting_sec = 2 # while job_result.status == "PROCESSING": # logger.info(f"Waiting {waiting_sec} seconds for job to be completed") # sleep(waiting_sec) # if waiting_sec > MAX_WAITING_SEC: # raise JobTimeOutError("Waited too long for job to be completed") # waiting_sec *= 2 # job_result = self.get_job_result(job_id) job_result = self._waiting_for_job_to_complete(job_id) raw_analytics_response = self.get_raw_analytics_response( job_result) all_responses.append(self.parse(raw_analytics_response)) return chain(*all_responses) def get_active_entity_ids(self): """ Step 1 of 'ANALYTICS' report generation process: Returns a list containing the ids of active entities over the requested time period Documentation: https://developer.twitter.com/en/docs/ads/analytics/api-reference/active-entities """ active_entities = ENTITY_OBJECTS[self.entity].active_entities( self.account, self.start_date, self.end_date) return [obj["entity_id"] for obj in active_entities] def get_job_ids(self, entity_ids): """ Step 2 of 'ANALYTICS' report generation process: Create asynchronous analytics jobs and return their ids for progress tracking Documentation: https://developer.twitter.com/en/docs/ads/analytics/api-reference/asynchronous """ return [ ENTITY_OBJECTS[self.entity].queue_async_stats_job( self.account, chunk_entity_ids, self.metric_groups, granularity=self.granularity, placement=self.placement, start_time=self.start_date, end_time=self.end_date, segmentation_type=self.segmentation_type, platform=self.platform, country=self.country, ).id for chunk_entity_ids in split_list(entity_ids, MAX_ENTITY_IDS_PER_JOB) ] @retry(wait=wait_exponential(multiplier=1, min=60, max=3600), stop=stop_after_delay(36000)) def _waiting_for_job_to_complete(self, job_id): """ Retrying to get job_result until job status is 'COMPLETED'. """ job_result = self.get_job_result(job_id) if job_result.status == "PROCESSING": raise Exception(f"Job {job_id} is still running.") else: return job_result def get_job_result(self, job_id): """ Step 3 of 'ANALYTICS' report generation process: Get job info to track its progress (job_result.status) and download report once completed (job_result.url) Documentation: https://developer.twitter.com/en/docs/ads/analytics/api-reference/asynchronous """ return ENTITY_OBJECTS[self.entity].async_stats_job_result( self.account, job_ids=[job_id]).first def get_raw_analytics_response(self, job_result): """ Step 4 of 'ANALYTICS' report generation process: Download raw response from job once completed Documentation: https://developer.twitter.com/en/docs/ads/analytics/api-reference/asynchronous """ return ENTITY_OBJECTS[self.entity].async_stats_job_data( self.account, url=job_result.url) def parse(self, raw_analytics_response): """ Parse a single raw response into a generator of JSON-like records. """ for entity_resp in raw_analytics_response["data"]: for entity_data in entity_resp["id_data"]: entity_records = [{ "id": entity_resp["id"], **{ mt: 0 if entity_data["metrics"][mt] is None else entity_data["metrics"][mt][i] for mt in entity_data["metrics"] }, } for i in range(raw_analytics_response["time_series_length"])] entity_records = self.add_daily_timestamps(entity_records) entity_records = self.add_segment(entity_records, entity_data) yield from entity_records def add_daily_timestamps(self, entity_records): """ Add daily timestamps to a list of records, if granularity is 'DAY'. """ if self.granularity == "DAY": period_items = self.get_daily_period_items() return [{ **entity_records[i], "date": period_items[i].strftime(REP_DATEFORMAT) } for i in range(len(entity_records))] return entity_records def get_daily_period_items(self): """ Returns a list of datetime instances representing each date contained in the requested period. Useful when granularity is set to 'DAY'. """ delta = self.end_date - self.start_date return [self.start_date + timedelta(days=i) for i in range(delta.days)] def add_segment(self, entity_records, entity_data): """ Add segment to a list of records, if a segmentation_type is requested. """ if self.segmentation_type: entity_segment = entity_data["segment"]["segment_name"] return [{ **rec, self.segmentation_type.lower(): entity_segment } for rec in entity_records] return entity_records def get_campaign_management_report(self): """ Get 'ENTITY' report through 'Campaign Management' endpoints of Twitter Ads API. Supported entities: FUNDING_INSTRUMENT, CAMPAIGN, LINE_ITEM, MEDIA_CREATIVE, PROMOTED_TWEET Documentation: https://developer.twitter.com/en/docs/ads/campaign-management/api-reference """ ACCOUNT_CHILD_OBJECTS = { "FUNDING_INSTRUMENT": self.account.funding_instruments(), "CAMPAIGN": self.account.campaigns(), "LINE_ITEM": self.account.line_items(), "MEDIA_CREATIVE": self.account.media_creatives(), "PROMOTED_TWEET": self.account.promoted_tweets(), } yield from [{ attr: getattr(entity_obj, attr, None) for attr in self.entity_attributes } for entity_obj in ACCOUNT_CHILD_OBJECTS[self.entity]] def get_cards_report(self): """ Get 'ENTITY' report through the 'Creatives' endpoint of Twitter Ads API. Supported entities: CARD Documentation: https://developer.twitter.com/en/docs/ads/creatives/api-reference/ """ for tweet in self.get_published_tweets_generator(): if "card_uri" in tweet: card_fetch = self.get_card_fetch(card_uri=tweet["card_uri"]) card_attributes = { attr: getattr(card_fetch, attr, None) for attr in self.entity_attributes } record = { "tweet_id": tweet["tweet_id"], "card_uri": tweet["card_uri"], **card_attributes, } yield record @retry( wait=wait_exponential(multiplier=60, max=300), stop=stop_after_delay(1200), retry=retry_if_exception_type(RateLimit), before_sleep=before_sleep_log(logger, LEVEL), ) def get_published_tweets_generator(self): return self.get_published_tweets() def get_published_tweets(self): """ Step 1 of 'ENTITY - CARD' report generation process: Returns details on 'PUBLISHED' tweets, as a generator of dictionaries Documentation: https://developer.twitter.com/en/docs/ads/creatives/api-reference/tweets """ resource = f"/{API_VERSION}/accounts/{self.account.id}/tweets" params = {"tweet_type": "PUBLISHED"} request = Request(self.client, "get", resource, params=params) yield from Cursor(None, request) @retry( wait=wait_exponential(multiplier=60, max=600), stop=stop_after_delay(1200), retry=retry_if_exception_type(RateLimit), before_sleep=before_sleep_log(logger, LEVEL), ) def get_card_fetch(self, card_uri): """ Step 2 of 'ENTITY - CARD' report generation process: Returns the CartFetch object associated with a specific card_uri Documentation: https://developer.twitter.com/en/docs/ads/creatives/api-reference/cards-fetch """ return CardsFetch.load(self.account, card_uris=[card_uri]).first @retry( wait=wait_exponential(multiplier=60, max=600), stop=stop_after_delay(3600), before_sleep=before_sleep_log(logger, LEVEL), ) def get_reach_report(self): """ Get 'REACH' report through the 'Reach and Average Frequency' endpoint of Twitter Ads API. Documentation: https://developer.twitter.com/en/docs/ads/analytics/api-reference/reach """ resource = f"/{API_VERSION}/stats/accounts/{self.account.id}/reach/{self.entity.lower()}s" entity_ids = self.get_active_entity_ids() for chunk_entity_ids in split_list(entity_ids, MAX_ENTITY_IDS_PER_JOB): try: params = { "account_id": self.account.id, f"{self.entity.lower()}_ids": ",".join(entity_ids), "start_time": self.start_date.strftime(API_DATEFORMAT), "end_time": self.end_date.strftime(API_DATEFORMAT), } request = Request(self.client, "get", resource, params=params) yield from Cursor(None, request) except Exception: ex_type, ex, tb = sys.exc_info() logger.warning( f"Failed to ingest post with error: {ex}. Traceback: {traceback.print_tb(tb)}" ) def add_request_or_period_dates(self, record): """ Add request_date, period_start_date and/or period_end_date to a JSON-like record. """ def check_add_period_date_to_report(): return (self.report_type == "ANALYTICS" and self.granularity == "TOTAL") or self.report_type == "REACH" if self.add_request_date_to_report: record["request_date"] = datetime.today().strftime(REP_DATEFORMAT) if check_add_period_date_to_report(): record["period_start_date"] = self.start_date.strftime( REP_DATEFORMAT) record["period_end_date"] = ( self.end_date - timedelta(days=1)).strftime(REP_DATEFORMAT) return record def read(self): if self.report_type == "ANALYTICS": entity_ids = self.get_active_entity_ids() total_jobs = (len(entity_ids) // MAX_ENTITY_IDS_PER_JOB) + 1 logger.info(f"Processing a total of {total_jobs} jobs") data = [] for chunk_entity_ids in split_list( entity_ids, MAX_ENTITY_IDS_PER_JOB * MAX_CONCURRENT_JOBS): job_ids = self.get_job_ids(chunk_entity_ids) data += self.get_analytics_report(job_ids) elif self.report_type == "REACH": data = self.get_reach_report() elif self.report_type == "ENTITY": if self.entity == "CARD": data = self.get_cards_report() else: data = self.get_campaign_management_report() def result_generator(): for record in data: yield self.add_request_or_period_dates(record) yield JSONStream("results_" + self.account.id, result_generator())
def home(request): Accounts = ['18ce559z5re', '18ce559wc04', '18ce557t3m2', '18ce552xv0y'] for AccountID in Accounts: CONSUMER_KEY = 'HDoSqCGCB3myJNoMP5RziL97w' CONSUMER_SECRET = '1WUOTQZsbNxIyVFpjCfSK4NslZqGUsvroYF4UdPFhGIVA4QPsh' ACCESS_TOKEN = '786549565717491713-3Qd2klEkIroIHYZ7f78ACd36qutNVHx' ACCESS_TOKEN_SECRET = '0aFaWFTpgXnrnhUCB2yZyGbcs8LF48Q1LQJiUt1VSvadn' ACCOUNT_ID = AccountID # initialize the client client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET, options={ 'handle_rate_limit': True, 'retry_max': 3, 'retry_delay': 10, 'retry_on_status': [404, 500, 503] }) # load the advertiser account instance account = client.accounts(ACCOUNT_ID) # print(account.name) yesterday = ("2020-03-05") + ("T00:00:00+08:00") today = ("2020-03-07") + ("T00:00:00+08:00") SpendList = [] DateList = [] # iterate through campaigns for camp in account.campaigns(): if camp.id: resource = f"/8/stats/accounts/" + AccountID + "/" #Enter Account Id Here params = { "entity": ENTITY.CAMPAIGN, "entity_ids": camp.id, "start_time": yesterday, "end_time": today, "granularity": GRANULARITY.TOTAL, "metric_groups": METRIC_GROUP.BILLING, "placement": PLACEMENT.ALL_ON_TWITTER } req = Request(client=client, method="GET", resource=resource, params=params) response = req.perform() spend_in_micros_value = response.body["data"][0]["id_data"][0][ "metrics"]["billed_charge_local_micro"] if spend_in_micros_value != None: spendAll = response.body["data"][0]["id_data"][0][ "metrics"]["billed_charge_local_micro"][0] spend = round((spendAll / 1000000), 2) SpendList.append(spend) else: spend = 0 SpendList.append(spend) StartTime = response.body["request"]["params"]["start_time"] # Subtraction one Day x = slice(10) startTime = (StartTime[x]) start = datetime.strptime(startTime, "%Y-%m-%d") Start = start + timedelta(days=1) EndTime = response.body["request"]["params"]["end_time"] # Subtraction one Day x = slice(10) endTime = (EndTime[x]) end = datetime.strptime(endTime, "%Y-%m-%d") End = end - timedelta(days=0) DateList.append(Start) DateList.append(End) else: print("No Camp") total = 0 for OneMonth in range(0, len(SpendList)): total = total + SpendList[OneMonth] account = (account.name) print("Total Spend= ", total) StartDate = (DateList[0]) EndDate = (DateList[1]) currentDate = datetime.today() print("Current Date= ", currentDate) DataFrame = DataSet(currentDate=currentDate, account=account, spend=total, StartDate=StartDate, EndDate=EndDate) DataFrame.save() return render(request, "index.html")
from twitter_ads.client import Client from twitter_ads.account import Account from twitter_ads.campaign import Campaign CONSUMER_KEY = "your consumer key" CONSUMER_SECRET = "your consumer secret" ACCESS_TOKEN = "access token" ACCESS_TOKEN_SECRET = "access token secret" ACCOUNT_ID = "account id" # initialize the client client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET) # load the advertiser account instance account = client.accounts(id=ACCOUNT_ID) # load and update a specific campaign campaign = account.campaigns().next() campaign.name = "updated campaign name" campaign.paused = True campaign.save() # iterate through campaigns for campaign in account.campaigns(): print(campaign.id)
def fetch_tailored_audience(self, data, syncData=False, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET): res = {} res['data'] = [] res['success'] = False account_id = data.get('account_id') if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id) resource = '/{api_version}/accounts/{account_id}/tailored_audiences?count=1000'.format( api_version=settings.TW_API_VERSION, account_id=account_id) response = Request(client, 'get', resource).perform() tailored_audiences = response.body['data'] next_cursor = None if response.body['next_cursor'] and response.body[ 'next_cursor'] is not 0: next_cursor = response.body['next_cursor'] while next_cursor is not 0: resource = '/{api_version}/accounts/{account_id}/tailored_audiences?cursor={next_cursor}&count=1000'.format( api_version=settings.TW_API_VERSION, account_id=account_id, next_cursor=next_cursor) response = Request(client, 'get', resource).perform() next_cursor = response.body['next_cursor'] or 0 tailored_audiences += response.body['data'] api_domain = 'https://ads.twitter.com' resource = '/accounts/{account_id}/apps.json'.format( account_id=account_id) response = Request(client, 'get', resource, domain=api_domain).perform() apps = response.body.get('apps_info', {}) app_table = [] for (k, v) in apps.iteritems(): app_store_identifier = v.get('app_store_identifier') app_name = v.get('title') if app_store_identifier and app_name: app_table.append({ 'id': app_store_identifier, 'name': app_name }) def replace_app_name(app_name): for app_info in app_table: app_name = app_name.replace(app_info['id'], app_info['name']) return app_name.replace('_', ' ') def human_format(num): magnitude = 0 while abs(num) >= 1000: magnitude += 1 num /= 1000.0 # add more suffixes if you need them return '%.2f%s' % (num, ['', 'K', 'M', 'G', 'T', 'P' ][magnitude]) for audience in tailored_audiences: audience['name'] = replace_app_name(audience['name']) if audience['audience_size']: audience['audience_size'] = human_format( audience['audience_size']) audience['name'] = '%s (%s users)' % ( audience['name'], audience['audience_size']) res['success'] = True res['data'] = tailored_audiences except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} if syncData and res['data'] and res['success']: res['sync'] = {} if isinstance(res['data'], (list, tuple)): sync_success = 0 sync_fail = 0 new_count = 0 existing_count = 0 for index, audience in enumerate(res['data'], start=0): audience_res = self.sync_tailored_audience( account_id_int, audience) if 'success' in audience_res and audience_res[ 'success'] is True: if audience_res['type'] == 'existing': existing_count += 1 if audience_res['type'] == 'new': new_count += 1 sync_success += 1 elif 'success' in audience_res and audience_res[ 'success'] is False: sync_fail += 1 res['sync']['type'] = {} res['sync']['type']['existing'] = existing_count res['sync']['type']['new'] = new_count res['sync']['total'] = sync_success if sync_fail == 0: res['sync']['success'] = True else: res['sync']['success'] = False elif isinstance(res['data'], dict): audience_res = self.sync_tailored_audience( account_id_int, res['data']) if 'success' in audience_res and audience_res[ 'success'] is True: res['data'] = audience_res['data'] res['sync']['success'] = audience_res['success'] res['sync']['type'] = {} res['sync']['type'][audience_res['type']] = 1 res['sync']['total'] = 1 elif 'success' in audience_res and audience_res[ 'success'] is False: res['data'] = audience_res['data'] res['sync']['success'] = audience_res['success'] res['sync']['message'] = audience_res['message'] return res
def fetch_campaigns(self, data, syncData=False, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET): res = {} res['data'] = [] res['success'] = False account_id = data.get('account_id') campaign_id = data.get('campaign_id') tw_campaign_id = data.get('tw_campaign_id') if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) if isinstance(tw_campaign_id, (int, long)): tw_campaign_id_int = tw_campaign_id tw_campaign_id = int_to_base36(tw_campaign_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id) # If Manage Campaign ID passed, fetch all Campaigns and find Manage Campaign if campaign_id: resource = '/{api_version}/accounts/{account_id}/campaigns?count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, 'get', resource).perform() if response.headers[ 'x-rate-limit-remaining'] == "0" and settings.TW_RATE_LIMIT_ALERT: send_twitter_alert_email({ "account_id": account_id, "endpoint": resource }) for campaign in response.body['data']: campaign_id_match = re.findall(r'\s*{(\d+)}\s*$', campaign['name'])[:1] if campaign_id_match and campaign_id_match[0] and int( campaign_id_match[0]) == int(campaign_id): res['data'].append(campaign) res['success'] = True else: if tw_campaign_id: resource = '/{api_version}/accounts/{account_id}/campaigns/{tw_campaign_id}?count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id, tw_campaign_id=tw_campaign_id) else: resource = '/{api_version}/accounts/{account_id}/campaigns?count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, 'get', resource).perform() if response.headers[ 'x-rate-limit-remaining'] == "0" and settings.TW_RATE_LIMIT_ALERT: send_twitter_alert_email({ "account_id": account_id, "endpoint": resource }) res['data'] = response.body['data'] next_cursor = None if response.body['next_cursor'] and response.body[ 'next_cursor'] is not 0: next_cursor = response.body['next_cursor'] while next_cursor is not 0: if tw_campaign_id: resource = '/{api_version}/accounts/{account_id}/campaigns/{tw_campaign_id}?cursor={next_cursor}&count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id, tw_campaign_id=tw_campaign_id, next_cursor=next_cursor) else: resource = '/{api_version}/accounts/{account_id}/campaigns?cursor={next_cursor}&count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id, next_cursor=next_cursor) response = Request(client, 'get', resource).perform() next_cursor = response.body['next_cursor'] or 0 res['data'] += response.body['data'] res['success'] = True except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} if syncData and res['data'] and res['success']: res['sync'] = {} if isinstance(res['data'], (list, tuple)): sync_success = 0 sync_fail = 0 new_count = 0 existing_count = 0 for index, api_campaign in enumerate(res['data'], start=0): campaign_res = self.sync_campaign(account_id_int, api_campaign) if 'success' in campaign_res and campaign_res[ 'success'] is True: if campaign_res['type'] == 'existing': existing_count += 1 if campaign_res['type'] == 'new': new_count += 1 sync_success += 1 elif 'success' in campaign_res and campaign_res[ 'success'] is False: sync_fail += 1 res['os_platform'] = campaign_res['os_platform'] res['sync']['type'] = {} res['sync']['type']['existing'] = existing_count res['sync']['type']['new'] = new_count res['sync']['total'] = sync_success if sync_fail == 0: res['sync']['success'] = True else: res['sync']['success'] = False elif isinstance(res['data'], dict): campaign_res = self.sync_campaign(account_id_int, res['data']) if 'success' in campaign_res and campaign_res[ 'success'] is True: res['data'] = campaign_res['data'] res['os_platform'] = campaign_res['os_platform'] res['sync']['success'] = campaign_res['success'] res['sync']['type'] = {} res['sync']['type'][campaign_res['type']] = 1 res['sync']['total'] = 1 elif 'success' in campaign_res and campaign_res[ 'success'] is False: res['data'] = campaign_res['data'] res['sync']['success'] = campaign_res['success'] res['sync']['message'] = campaign_res['message'] return res
def batch_create_update_campaign( self, data, account_id, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET, request_type="post"): res = {} res['success'] = False campaign_id_int = None if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) if account_id is None: res = { 'data': [], 'success': False, 'message': "Missing Twitter Account ID" } return res if isinstance(data, (list, tuple)): post_data = [] for campaign in data: campaign_data = {} params = {} params['daily_budget_amount_local_micro'] = campaign.get( 'daily_budget_amount_local_micro', None) params['duration_in_days'] = campaign.get( 'duration_in_days', None) params['end_time'] = campaign.get('end_time', None) params['frequency_cap'] = campaign.get('frequency_cap', None) params['funding_instrument_id'] = campaign.get( 'funding_instrument_id', None) params['name'] = campaign.get('name', None) if campaign.get('paused', None) is not None: params['paused'] = 'true' if campaign.get( 'paused') else 'false' params['standard_delivery'] = str( campaign.get('standard_delivery')).lower() if campaign.get( 'standard_delivery') else None params['start_time'] = campaign.get('start_time', None) params['total_budget_amount_local_micro'] = campaign.get( 'total_budget_amount_local_micro', None) # total_budget_amount_local_micro = 0 is not permitted if not params['total_budget_amount_local_micro']: params['total_budget_amount_local_micro'] = None params = dict((k, v) for k, v in params.iteritems() if v is not None and v is not "") if request_type == 'post': campaign_data['operation_type'] = 'Create' if request_type == 'put': campaign_data['operation_type'] = 'Update' campaign_data['params'] = params post_data.append(campaign_data) client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX # Split up requests into batches of 20 batch = [] batches = [] for x in range(0, len(post_data), 20): batch = post_data[x:x + 20] batches.append(batch) success_batch = [] error_batch = [] error_details = [] success = False error = False for batch_post in batches: try: account = client.accounts(account_id) headers = {"Content-Type": "application/json"} resource = '/{api_version}/batch/accounts/{account_id}/campaigns'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, 'post', resource, body=json.dumps(batch_post), headers=headers).perform() if response.code == 200 or response.code == 201: success = True success_batch.extend(response.body['data']) except Error as e: error = True if e.response.body.get('operation_errors', None) is not None: for err in e.response.body.get('operation_errors'): if err: if isinstance(err, dict): err = [err] error_details.extend(err) if e.response.body.get('errors', None) is not None: for err in e.response.body.get('errors'): if err: if isinstance(err, dict): err = [err] error_details.extend(err) error_batch.extend(batch_post) except Exception as e: res = {'data': [], 'success': False, 'message': str(e)} error_batch.extend(batch_post) if success_batch and success: res['sync'] = {} if isinstance(success_batch, dict): success_batch = [success_batch] sync_success = 0 sync_fail = 0 new_count = 0 existing_count = 0 for index, api_campaign in enumerate(success_batch, start=0): campaign_res = self.sync_campaign(account_id_int, api_campaign) if 'success' in campaign_res and campaign_res[ 'success'] is True: if campaign_res['type'] == 'existing': existing_count += 1 if campaign_res['type'] == 'new': new_count += 1 sync_success += 1 elif 'success' in campaign_res and campaign_res[ 'success'] is False: sync_fail += 1 res['sync']['type'] = {} res['sync']['type']['existing'] = existing_count res['sync']['type']['new'] = new_count res['sync']['total'] = sync_success if sync_fail == 0: res['sync']['success'] = True else: res['sync']['success'] = False res['success'] = success res['count'] = {} res['count']['success'] = len(success_batch) res['count']['total'] = len(data) res['count']['error'] = len(error_batch) res['data'] = success_batch if error: res['success'] = False res['error'] = {} res['error']['data'] = error_batch res['error']['messages'] = filter(None, error_details) return res elif isinstance(data, dict): if request_type == 'post': return self.create(data, oauth_token, oauth_token_secret) if request_type == 'put': return self.update(data, oauth_token, oauth_token_secret)
from twitter_ads.client import Client from twitter_ads.creative import CardsFetch from twitter_ads.http import Request CONSUMER_KEY = '' CONSUMER_SECRET = '' ACCESS_TOKEN = '' ACCESS_TOKEN_SECRET = '' ACCOUNT_ID = '' # initialize the client client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET) # load the advertiser account instance account = client.accounts(ACCOUNT_ID) # retrieve a Tweet tweet_id = '973002610033610753' # use one of your own Tweets resource = '/1.1/statuses/show/{id}.json'.format(id=tweet_id) domain = 'https://api.twitter.com' params = {'include_card_uri' : 'true'} response = Request(client, 'get', resource, domain=domain, params=params).perform() card_uri = response.body['card_uri'] # Tweet must include a card_uri card # fetch by card_uri cf = CardsFetch(account) card = cf.load(account, card_uri=card_uri) card.card_type # 'VIDEO_POLLS' card.id # '5g83p'
def fetch_tweet(self, data, syncData=False, oauth_token=settings.TW_ACCESS_TOKEN, oauth_secret=settings.TW_ACCESS_SECRET): res = {} res['success'] = True account_id = data.get('account_id') tweet_id = data.get('tweet_id') if isinstance(account_id,(int,long)): account_id_int = account_id account_id = int_to_base36(account_id) if not _cache.get(account_id): try: tw_account = TwitterAccount.objects_raw.filter(tw_account_id=account_id_int).first() if tw_account.promotable_user_id.tw_twitter_user_id: _cache[account_id] = tw_account.promotable_user_id.tw_twitter_user_id except TwitterUser.DoesNotExist: _cache[account_id] = 0 except TwitterAccount.DoesNotExist: _cache[account_id] = 0 if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: api_domain = 'https://api.twitter.com' resource = '/{api_version}/statuses/show.json?id={tweet_id}'.format(api_version="1.1", tweet_id=tweet_id) response = Request(client, 'get', resource, domain=api_domain).perform() entities = response.body['entities'] #print response.headers['x-rate-limit-remaining'] if response.headers['x-rate-limit-remaining'] == "0" and settings.TW_RATE_LIMIT_ALERT: send_twitter_alert_email({"account_id": account_id, "endpoint": resource}) expanded_url = None if entities and entities['urls'] and entities['urls'][0] and entities['urls'][0]['expanded_url']: expanded_url = entities['urls'][0]['expanded_url'] account = client.accounts(account_id) as_user_id = ('?as_user_id=%s' % _cache[account_id]) if _cache[account_id] else '' resource = '/{api_version}/accounts/{account_id}/tweet/preview/{tweet_id}{as_user_id}'.format(api_version=settings.TW_API_VERSION, account_id=account.id, tweet_id=tweet_id, as_user_id=as_user_id) response = Request(client, 'get', resource).perform() res['data'] = response.body['data'] res['card_url'] = expanded_url except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = { 'data': {}, 'success': False, 'message': str(e) } return res
def create_update_promoted_tweet( self, data, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET, request_type="post"): res = {} res['sync'] = {} account_id = data.get('account_id', None) line_item_id = data.get('line_item_id', None) tweet_ids = data.get('tweet_ids', None) promoted_tweet_id = data.get('promoted_tweet_id', None) line_item_id_int = None line_item_id_int = line_item_id line_item_id_base_36 = int_to_base36(line_item_id) account_id_int = account_id account_id_base36 = int_to_base36(account_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res if request_type == 'put' or request_type == 'delete': if promoted_tweet_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Promoted Tweet ID" } return res if request_type == 'post': if tweet_ids is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Tweet IDs" } return res if line_item_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Line Item ID" } return res params = {} params['display_properties'] = data.get('display_properties', None) params['tweet_ids'] = data.get('tweet_ids', None) params['line_item_id'] = line_item_id_base_36 params = dict((k, v) for k, v in params.iteritems() if v is not None and v is not "") client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id_base36) if request_type == 'put' or request_type == 'delete': resource = '/{api_version}/accounts/{account_id}/promoted_tweets/{promoted_tweet_id}'.format( api_version=settings.TW_API_VERSION, account_id=account.id, promoted_tweet_id=promoted_tweet_id) elif request_type == 'post': resource = '/{api_version}/accounts/{account_id}/promoted_tweets'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, request_type, resource, params=params).perform() if response.code == 200 or response.code == 201: res['success'] = True res['data'] = response.body['data'] if res['data'] and res['success']: sync_success = 0 sync_fail = 0 new_count = 0 existing_count = 0 deleted_count = 0 if request_type == 'delete': res['data'] = [res['data']] for index, api_line_item_promoted_tweet in enumerate( res['data'], start=0): line_item_id_int = base36_to_int( api_line_item_promoted_tweet['line_item_id']) api_line_item_promoted_tweet['account_id'] = account_id line_item_promoted_tweet_res = self.sync_promoted_tweet( account_id_int, line_item_id_int, api_line_item_promoted_tweet) if 'success' in line_item_promoted_tweet_res and line_item_promoted_tweet_res[ 'success'] is True: if 'skip' in line_item_promoted_tweet_res: continue if line_item_promoted_tweet_res['type'] == 'existing': existing_count += 1 if line_item_promoted_tweet_res['type'] == 'new': new_count += 1 if line_item_promoted_tweet_res['type'] == 'delete': deleted_count += 1 sync_success += 1 elif 'success' in line_item_promoted_tweet_res and line_item_promoted_tweet_res[ 'success'] is False: sync_fail += 1 res['sync']['success'] = sync_fail == 0 res['sync']['type'] = {} res['sync']['type']['existing'] = existing_count res['sync']['type']['new'] = new_count res['sync']['type']['delete'] = deleted_count except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} return res
def batch_create_update_line_item( self, data, account_id, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET, request_type="post"): res = {} res['success'] = False campaign_id_int = None if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) if account_id is None: res = { 'data': [], 'success': False, 'message': "Missing Twitter Account ID" } return res if isinstance(data, (list, tuple)): post_data = [] for line_item in data: line_item_data = {} params = {} params['bid_amount_local_micro'] = line_item.get( 'bid_amount_local_micro', None) params['bid_type'] = line_item.get('bid_type', None) params['bid_unit'] = line_item.get('bid_unit', None) params['campaign_id'] = line_item.get('campaign_id', None) params['categories'] = line_item.get('categories', None) params['charge_by'] = line_item.get('charge_by', None) params['end_time'] = line_item.get('end_time', None) params['include_sentiment'] = line_item.get( 'include_sentiment', None) params['line_item_id'] = line_item.get('line_item_id', None) params['name'] = line_item.get('name', None) params['objective'] = line_item.get('objective', 'APP_INSTALLS') params['primary_web_event_tag'] = line_item.get( 'primary_web_event_tag', None) params['optimization'] = line_item.get('optimization', None) params['paused'] = str(line_item.get( 'paused')).lower() if line_item.get('paused') else None params['placements'] = line_item.get('placements', 'ALL_ON_TWITTER') params['product_type'] = line_item.get('product_type', 'PROMOTED_TWEETS') params['start_time'] = line_item.get('start_time', None) params['total_budget_amount_local_micro'] = line_item.get( 'total_budget_amount_local_micro', None) # total_budget_amount_local_micro = 0 is not permitted if not params['total_budget_amount_local_micro']: params['total_budget_amount_local_micro'] = None params = dict((k, v) for k, v in params.iteritems() if v is not None and v is not "") if request_type == 'post': line_item_data['operation_type'] = 'Create' if request_type == 'put': line_item_data['operation_type'] = 'Update' line_item_data['params'] = params post_data.append(line_item_data) client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX # Split up requests into batches of 20 batch = [] batches = [] for x in range(0, len(post_data), 20): batch = post_data[x:x + 20] batches.append(batch) success_batch = [] error_batch = [] error_details = [] success = False error = False for batch_post in batches: try: account = client.accounts(account_id) headers = {"Content-Type": "application/json"} resource = '/{api_version}/batch/accounts/{account_id}/line_items'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, 'post', resource, body=json.dumps(batch_post), headers=headers).perform() if response.code == 200 or response.code == 201: success = True success_batch.extend(response.body['data']) except Error as e: error = True if e.response.body.get('operation_errors', None) is not None: for err in e.response.body.get('operation_errors'): if err: if isinstance(err, dict): err = [err] error_details.extend(err) if e.response.body.get('errors', None) is not None: for err in e.response.body.get('errors'): if err: if isinstance(err, dict): err = [err] error_details.extend(err) error_batch.extend(batch_post) except Exception as e: res = {'data': [], 'success': False, 'message': str(e)} error_batch.extend(batch_post) if success_batch and success: res['sync'] = {} if isinstance(success_batch, dict): success_batch = [success_batch] sync_success = 0 sync_fail = 0 new_count = 0 existing_count = 0 for index, api_line_item in enumerate(success_batch, start=0): #campaign_id could be different in line item bach campaign_id_int = base36_to_int( api_line_item['campaign_id']) line_item_res = self.sync_line_item( account_id_int, campaign_id_int, api_line_item) if 'success' in line_item_res and line_item_res[ 'success'] is True: if line_item_res['type'] == 'existing': existing_count += 1 if line_item_res['type'] == 'new': new_count += 1 sync_success += 1 elif 'success' in line_item_res and line_item_res[ 'success'] is False: sync_fail += 1 res['sync']['type'] = {} res['sync']['type']['existing'] = existing_count res['sync']['type']['new'] = new_count res['sync']['total'] = sync_success if sync_fail == 0: res['sync']['success'] = True else: res['sync']['success'] = False res['success'] = success res['count'] = {} res['count']['success'] = len(success_batch) res['count']['total'] = len(data) res['count']['error'] = len(error_batch) res['data'] = success_batch if error: res['success'] = False res['error'] = {} res['error']['data'] = error_batch res['error']['messages'] = filter(None, error_details) return res elif isinstance(data, dict): if request_type == 'post': return self.create(data, oauth_token, oauth_token_secret) if request_type == 'put': return self.update(data, oauth_token, oauth_token_secret)
def create_update_line_item(self, data, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET, request_type="post"): res = {} res['sync'] = {} account_id = data.get('account_id', None) campaign_id = data.get('campaign_id', None) line_item_id = data.get('line_item_id', None) campaign_id_int = None if isinstance(campaign_id, (int, long)): campaign_id_int = campaign_id campaign_id = int_to_base36(campaign_id) data['campaign_id'] = campaign_id if isinstance(line_item_id, (int, long)): line_item_id_int = line_item_id line_item_id = int_to_base36(line_item_id) if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) if account_id is None: res = { 'data': [], 'success': False, 'message': "Missing Twitter Account ID" } return res if request_type == 'post': if campaign_id is None: res = { 'data': [], 'success': False, 'message': "Missing Twitter Campaign ID" } return res if request_type == 'put': if line_item_id is None: res = { 'data': [], 'success': False, 'message': "Missing Twitter Line Item ID" } return res params = {} params['advertiser_domain'] = data.get('advertiser_domain', None) # automatically_set_bid and bid_type cannot be set in the same request # See https://dev.twitter.com/ads/reference/post/accounts/%3Aaccount_id/line_items#api-param-line-item-bid_type if data.get('automatically_select_bid', False) is True: params['automatically_select_bid'] = str(True).lower() else: params['bid_type'] = data.get('bid_type', None) params['bid_amount_local_micro'] = data.get( 'bid_amount_local_micro', None) params['bid_amount_local_micro'] = data.get('bid_amount_local_micro', None) params['bid_type'] = data.get('bid_type', None) params['bid_unit'] = data.get('bid_unit', None) params['campaign_id'] = data.get('campaign_id', None) params['categories'] = data.get('categories', None) params['charge_by'] = data.get('charge_by', None) params['end_time'] = data.get('end_time', None) params['include_sentiment'] = data.get('include_sentiment', 'POSITIVE_ONLY') params['name'] = data.get('name', None) params['objective'] = data.get('objective', 'APP_INSTALLS') params['optimization'] = data.get('optimization', None) if data.get('paused', None) is not None: params['paused'] = 'true' if data.get('paused') else 'false' params['placements'] = data.get('placements', 'ALL_ON_TWITTER') params['product_type'] = data.get('product_type', 'PROMOTED_TWEETS') params['start_time'] = data.get('start_time', None) params['total_budget_amount_local_micro'] = data.get( 'total_budget_amount_local_micro', None) # total_budget_amount_local_micro = 0 is not permitted if not params['total_budget_amount_local_micro']: params['total_budget_amount_local_micro'] = None params = dict((k, v) for k, v in params.iteritems() if v is not None and v is not "") client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id) if request_type == 'put': resource = '/{api_version}/accounts/{account_id}/line_items/{line_item_id}'.format( api_version=settings.TW_API_VERSION, account_id=account.id, line_item_id=line_item_id) elif request_type == 'post': resource = '/{api_version}/accounts/{account_id}/line_items'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, request_type, resource, params=params).perform() if response.code == 200 or response.code == 201: res['success'] = True res['data'] = response.body['data'] if res['data'] and res['success']: if campaign_id_int is None and res['data']['campaign_id']: campaign_id_int = base36_to_int(res['data']['campaign_id']) line_item_res = self.sync_line_item(account_id_int, campaign_id_int, res['data']) if 'success' in line_item_res and line_item_res[ 'success'] is True: res['data'] = line_item_res['data'] res['sync']['success'] = line_item_res['success'] res['sync']['type'] = {} res['sync']['total'] = 1 res['sync']['type'][line_item_res['type']] = 1 elif 'success' in line_item_res and line_item_res[ 'success'] is False: res['data'] = line_item_res['data'] res['sync']['success'] = line_item_res['success'] res['sync']['message'] = line_item_res['message'] except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} return res
def get_line_item(self, data, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET): res = {} account_id = data.get('account_id') line_item_id = data.get('line_item_id') if isinstance(line_item_id, (int, long)): line_item_id = int_to_base36(line_item_id) if isinstance(account_id, (int, long)): account_id = int_to_base36(account_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res if line_item_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Line Item ID" } return res client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id) resource = '/{api_version}/accounts/{account_id}/line_items/{line_item_id}?count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id, line_item_id=line_item_id) response = Request(client, 'get', resource).perform() res['data'] = response.body['data'] res['success'] = True except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} return res
def fetch_app_cards(self, data, syncData=False, oauth_token=settings.TW_ACCESS_TOKEN, oauth_secret=settings.TW_ACCESS_SECRET): res = {} account_id = data.get('account_id') if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) else: account_id_int = base36_to_int(account_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: res['data'] = [] account = client.accounts(account_id) resource = '/{api_version}/accounts/{account_id}/cards/app_download'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, 'get', resource).perform() for card in response.body['data']: res['data'].append(card) resource = '/{api_version}/accounts/{account_id}/cards/image_app_download'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, 'get', resource).perform() for card in response.body['data']: res['data'].append(card) resource = '/{api_version}/accounts/{account_id}/cards/video_app_download'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, 'get', resource).perform() if response.headers[ 'x-rate-limit-remaining'] == "0" and settings.TW_RATE_LIMIT_ALERT: send_twitter_alert_email({ "account_id": account_id, "endpoint": resource }) for card in response.body['data']: res['data'].append(card) res['success'] = True except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} if syncData and res['data'] and res['success']: res['sync'] = {} if isinstance(res['data'], (list, tuple)): sync_success = 0 sync_fail = 0 new_count = 0 existing_count = 0 for index, api_app_card in enumerate(res['data'], start=0): app_card_res = self.sync_app_card(account_id_int, api_app_card) if 'success' in app_card_res and app_card_res[ 'success'] is True: if app_card_res['type'] == 'existing': existing_count += 1 if app_card_res['type'] == 'new': new_count += 1 sync_success += 1 elif 'success' in app_card_res and app_card_res[ 'success'] is False: sync_fail += 1 res['sync']['type'] = {} res['sync']['type']['existing'] = existing_count res['sync']['type']['new'] = new_count res['sync']['total'] = sync_success if sync_fail == 0: res['sync']['success'] = True else: res['sync']['success'] = False elif isinstance(res['data'], dict): app_card_res = self.sync_app_card(account_id_int, res['data']) if 'success' in app_card_res and app_card_res[ 'success'] is True: res['data'] = app_card_res['data'] res['sync']['success'] = app_card_res['success'] res['sync']['type'] = {} res['sync']['total'] = 1 res['sync']['type'][app_card_res['type']] = 1 # sync_success if 'success' in app_card_res and app_card_res[ 'success'] is False: res['data'] = app_card_res['data'] res['sync']['success'] = app_card_res['success'] res['sync']['message'] = app_card_res['message'] return res
import hashlib from twitter_ads.client import Client from twitter_ads.audience import CustomAudience CONSUMER_KEY = 'your consumer key' CONSUMER_SECRET = 'your consumer secret' ACCESS_TOKEN = 'access token' ACCESS_TOKEN_SECRET = 'access token secret' ACCOUNT_ID = 'account id' # initialize the client client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET) # load the advertiser account instance account = client.accounts(ACCOUNT_ID) # create a new custom audience audience = CustomAudience.create(account, 'test CA') # sample user # all values musth be sha256 hashed email_hash = hashlib.sha256("*****@*****.**").hexdigest() # create payload user = [{ "operation_type": "Update", "params": { "users": [{ "email": [email_hash] }]
from twitter_ads.cursor import Cursor from twitter_ads.http import Request from twitter_ads.error import Error CONSUMER_KEY = 'your consumer key' CONSUMER_SECRET = 'your consumer secret' ACCESS_TOKEN = 'user access token' ACCESS_TOKEN_SECRET = 'user access token secret' ADS_ACCOUNT = '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 account = client.accounts(ADS_ACCOUNT) # using the Request object you can manually request any # twitter ads api resource that you want. resource = '/' + API_VERSION + '/accounts/{account_id}/features'.format( account_id=account.id) params = {'feature_keys': 'AGE_TARGETING,CPI_CHARGING'} # try, build and execute the request with error handling try: response = Request(client, 'get', resource, params=params).perform() print(response.body['data'][0]) except Error as e: # see twitter_ads.error for more details print(e.details)
def create_update_campaign(self, data, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET, request_type="post"): res = {} res['sync'] = {} res['success'] = False account_id = data.get('account_id') campaign_id = data.get('tw_campaign_id') if isinstance(campaign_id, (int, long)): campaign_id_int = campaign_id campaign_id = int_to_base36(campaign_id) if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res if request_type == 'put': if campaign_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Campaign ID" } return res params = {} params['daily_budget_amount_local_micro'] = data.get( 'daily_budget_amount_local_micro', None) params['duration_in_days'] = data.get('duration_in_days', None) params['end_time'] = data.get('end_time', None) params['frequency_cap'] = data.get('frequency_cap', None) params['funding_instrument_id'] = data.get('funding_instrument_id', None) params['name'] = data.get('name', None) if data.get('paused', None) is not None: params['paused'] = 'true' if data.get('paused') else 'false' params['standard_delivery'] = str(data.get('standard_delivery')).lower( ) if data.get('standard_delivery') else None params['start_time'] = data.get('start_time', None) params['total_budget_amount_local_micro'] = data.get( 'total_budget_amount_local_micro', None) # total_budget_amount_local_micro = 0 is not permitted if not params['total_budget_amount_local_micro']: params['total_budget_amount_local_micro'] = None params = dict((k, v) for k, v in params.iteritems() if v is not None and v is not "") client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id) if request_type == 'put': resource = '/{api_version}/accounts/{account_id}/campaigns/{campaign_id}'.format( api_version=settings.TW_API_VERSION, account_id=account.id, campaign_id=campaign_id) elif request_type == 'post': resource = '/{api_version}/accounts/{account_id}/campaigns'.format( api_version=settings.TW_API_VERSION, account_id=account.id) response = Request(client, request_type, resource, params=params).perform() if response.code == 200 or response.code == 201: res['success'] = True res['data'] = response.body['data'] if res['data'] and res['success']: campaign_res = self.sync_campaign(account_id_int, res['data']) if 'success' in campaign_res and campaign_res[ 'success'] is True: res['data'] = campaign_res['data'] res['sync']['success'] = campaign_res['success'] res['sync']['type'] = {} res['sync']['type'][campaign_res['type']] = 1 res['sync']['total'] = 1 elif 'success' in campaign_res and campaign_res[ 'success'] is False: res['data'] = campaign_res['data'] res['sync']['success'] = campaign_res['success'] res['sync']['message'] = campaign_res['message'] except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} return res
from twitter_ads.client import Client from twitter_ads.campaign import Tweet from twitter_ads.creative import PromotedTweet, WebsiteCard CONSUMER_KEY = 'your consumer key' CONSUMER_SECRET = 'your consumer secret' ACCESS_TOKEN = 'user access token' ACCESS_TOKEN_SECRET = 'user access token secret' ADS_ACCOUNT = '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) 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)
def fetch_line_items(self, data, syncData=False, oauth_token=settings.TW_ACCESS_TOKEN, oauth_token_secret=settings.TW_ACCESS_SECRET): res = {} res['data'] = [] res['success'] = False account_id = data.get('account_id') campaign_id = data.get('campaign_id') line_item_id = data.get('line_item_id') campaign_id_int = None if isinstance(account_id, (int, long)): account_id_int = account_id account_id = int_to_base36(account_id) if isinstance(campaign_id, (int, long)): campaign_id_int = campaign_id campaign_id = int_to_base36(campaign_id) if isinstance(line_item_id, (int, long)): line_item_id = int_to_base36(line_item_id) if account_id is None: res = { 'data': {}, 'success': False, 'message': "Missing Twitter Account ID" } return res client = Client(settings.TW_CONSUMER_KEY, settings.TW_CONSUMER_SECRET, oauth_token, oauth_token_secret) if settings.TW_SANDBOX: client.sandbox = settings.TW_SANDBOX try: account = client.accounts(account_id) resource = '/{api_version}/accounts/{account_id}/line_items?with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id) if campaign_id is not None: resource = '/{api_version}/accounts/{account_id}/line_items?campaign_ids={campaign_id}&count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id, campaign_id=campaign_id) response = Request(client, 'get', resource).perform() if response.headers[ 'x-rate-limit-remaining'] == "0" and settings.TW_RATE_LIMIT_ALERT: send_twitter_alert_email({ "account_id": account_id, "endpoint": resource }) res['data'] = response.body['data'] next_cursor = None if response.body['next_cursor'] and response.body[ 'next_cursor'] is not 0: next_cursor = response.body['next_cursor'] while next_cursor is not 0: resource = '/{api_version}/accounts/{account_id}/line_items?cursor={next_cursor}&count=1000&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id, next_cursor=next_cursor) if campaign_id is not None: resource = '/{api_version}/accounts/{account_id}/line_items?campaign_ids={campaign_id}&count=1000&cursor={next_cursor}&with_deleted=true'.format( api_version=settings.TW_API_VERSION, account_id=account.id, campaign_id=campaign_id, next_cursor=next_cursor) response = Request(client, 'get', resource).perform() next_cursor = response.body['next_cursor'] or 0 res['data'] += response.body['data'] res['success'] = True except Error as e: code = None if e.code: code = e.code elif e.details[0]['code']: code = e.details[0]['code'] res = { 'data': {}, 'success': False, 'message': e.details[0]['message'] if e.details and e.details[0] and e.details[0]['message'] else '', 'errors': { str(code): True } if code else {} } except Exception as e: res = {'data': {}, 'success': False, 'message': str(e)} if syncData and res['data'] and res['success']: res['sync'] = {} if isinstance(res['data'], (list, tuple)): sync_success = 0 sync_fail = 0 new_count = 0 existing_count = 0 for index, api_line_item in enumerate(res['data'], start=0): if campaign_id_int is None: campaign_id_int = base36_to_int( api_line_item['campaign_id']) line_item_res = self.sync_line_item( account_id_int, campaign_id_int, api_line_item) if 'success' in line_item_res and line_item_res[ 'success'] is True: if line_item_res['type'] == 'existing': existing_count += 1 if line_item_res['type'] == 'new': new_count += 1 sync_success += 1 elif 'success' in line_item_res and line_item_res[ 'success'] is False: sync_fail += 1 res['sync']['type'] = {} res['sync']['type']['existing'] = existing_count res['sync']['type']['new'] = new_count res['sync']['total'] = sync_success if sync_fail == 0: res['sync']['success'] = True else: res['sync']['success'] = False elif isinstance(res['data'], dict): line_item_res = self.sync_line_item(account_id_int, campaign_id_int, res['data']) if 'success' in line_item_res and line_item_res[ 'success'] is True: res['data'] = line_item_res['data'] res['sync']['success'] = line_item_res['success'] res['sync']['type'] = {} res['sync']['total'] = 1 res['sync']['type'][line_item_res['type']] = 1 elif 'success' in line_item_res and line_item_res[ 'success'] is False: res['data'] = line_item_res['data'] res['sync']['success'] = line_item_res['success'] res['sync']['message'] = line_item_res['message'] return res