def check_parameters(self): ''' @summary: Check that all the parameters given, match the ones set as required and optional for this block. @raise WFBridgeException: if there is a mismatch with the parameters. ''' all_params = [] for pv in self.parameters.itervalues(): all_params.extend(pv.keys()) all_params = set(all_params) req = set(self.required_parameters) opt = set(self.optional_parameters) # Check all required parameters are set if not req.issubset(all_params): missing = ",".join(req - all_params) err = "Missing required parameters {}".format(missing) raise WFBrigeException(err) # Now check that the parameters that are not required are optional if not (all_params - req).issubset(opt): unused_parameters = ",".join(all_params - req - opt) err = "{} have been specified but are not required nor optional" raise WFBrigeException(err.format(unused_parameters)) for block in self.blocks: block.check_parameters()
def _check_viability(self): def check_not_none(name, value): if value is None: raise WFBrigeException("{} is required".format(name)) if self.exclude_html_validation: check_not_none("ecm_html", self.ecm_html) else: if self.html is None and self.html_zip is None: err = "At least a zip or an html should be provided" raise WFBrigeException(err) if self.html is not None and self.html_zip is not None: err = "Only a zip or an html should be provided" raise WFBrigeException(err) if len(self.test_seed_lists) > 0: check_not_none("seeds_provider", self.seeds_provider.name) check_not_none("seeds_sender_name", self.seeds_provider.sender_name) check_not_none("seeds_sender_email", self.seeds_provider.sender_email) check_not_none("subject", self.subject) check_not_none("email_creative_id", self.email_creative_id) check_not_none("audience_provider", self.audience_provider.name) check_not_none("audience_sender_name", self.audience_provider.sender_name) check_not_none("audience_sender_email", self.audience_provider.sender_email)
def __task_from_name(self, task_name, tasks, prj): # Task identifier is a task number in the project block if type(task_name) == int: if len(tasks) < task_name: tmpl = prj.get_template_id() err = "Project Template {} has {} tasks. Task {} referenced " \ "from task parameter values." err = err.format(tmpl, len(tasks), task_name) raise WFBrigeException(err) return tasks[task_name - 1] # Task is being identified by its name mtasks = [t for t in tasks if t.name == task_name] if len(mtasks) == 1: return mtasks[0] elif len(mtasks) == 0: tmpl = prj.get_template_id() err = "Project Template {} does not have task name {} referenced " \ "from task parameter values." err = err.format(tmpl, task_name) raise WFBrigeException(err) else: tmpl = prj.get_template_id() err = "Project Template {} has more than one task named as {}" err = err.format(tmpl, task_name) raise WFBrigeException(err)
def __fullfill_project_type(self): ''' @summary: Fullfill self.project_type based on the project that will be cancel (self.wf_project_id) @raise WFBridgeException: if the project has an unsupported project type to cancel. ''' prj = WFProject(self.wf, self.wf_project_id) params = prj.get_param_values() if "Project Type" not in params: WFBrigeException("Unknown Project Type - {} is missing Project " "Type custom form field".format(prj)) if params["Project Type"] not in self.supported_project_types: WFBrigeException("Project Type {} not supported for canceling " "project {}".format(prj)) self.project_type = params["Project Type"]
def check_file_extension(name, file_name, allowed_extensions=(".html", )): if not file_name.lower().endswith(allowed_extensions): raise WFBrigeException( "{}: {} file hasn't an allowed extensions ({})".format( name, file_name, ",".join(allowed_extensions)))
def check_length(field_name, collection, min_length=0, max_length=sys.maxint): if len(collection) < min_length or len(collection) > max_length: raise WFBrigeException( "{}: length ({}) is not between {} to {}".format( field_name, len(collection), min_length, max_length))
def set_audience_identifier(self, audience_identifier): if audience_identifier not in self.AUDIENCE_FILE_INDENTIFIERS: m = "Invalid audience identifier {}. Possible values are {}" err = m.format(audience_identifier, ",".join(self.AUDIENCE_FILE_INDENTIFIERS)) raise WFBrigeException(err) self.audience_identifier = audience_identifier return self
def add_ad_group(self, ad_group): """ Ad Group kwargs: {} Creative common kwargs: {} """.format(self.ad_group_fields, self.creative_common_fields) allowed_keys = self.ad_group_fields for k, v in ad_group.items(): if k not in allowed_keys: raise WFBrigeException('Invalid Key {}'.format(k)) elif k == 'creatives': for creative in v: creative_allowed_keys = self.creative_type_allowed_fields[creative['creative_type']] for creative_key, creative_value in creative.items(): if creative_key not in creative_allowed_keys: raise WFBrigeException('Invalid Creative Key {}'.format(creative_key)) self._ad_groups.append(ad_group)
def set_suppression_type(self, suppression_type): ''' @param suppression_type: one_per_person, one_per_household ''' if suppression_type not in self.SUPPRESSION_TYPES: m = "Invalid suppression type {}. Possible values are {}" raise WFBrigeException( m.format(suppression_type, ",".join(self.SUPPRESSION_TYPES))) self.suppression_type = suppression_type return self
def _check_viability(self): if self.project_type is None: m = "You must specify the type of data project to be created (use"\ " set_b2c or set_match_and_export)" raise WFBrigeException(m) if self.project_type == "b2c": self._check_viability_b2c() elif self.project_type == "m&e": self._check_viability_match_and_export() else: raise Exception("Invalid data project type")
def build(self): """ @summary: build the Workfront project. @raise WFBrigeException @return: WFProject object """ if not self._ad_groups: raise WFBrigeException('The project does not have any ad_groups. Please use add_ad_group to add them.') project = WFProjectSocialContainer(self.project_name) # Blocks order_review_block = WFSocialOrderReviewBlock() data_block = WFSocialDataBlock() setup_block = WFSocialSetupBlock() setup_block.campaign_title = self._campaign_title setup_block.fb_page_id = self._fb_page_id setup_block.fb_ig_acc_id = self._fb_ig_acc_id setup_block.fb_advertising_objective = self._fb_advertising_objective setup_block.fb_offer = self._fb_offer setup_block.fb_apply_block_list = self._fb_apply_block_list ad_group_setup_blocks = [] for ad_group in self._ad_groups: ad_group_setup_block = WFSocialAdGroupSetupBlock() for creative in ad_group['creatives']: creative_upload_dict = {k: creative[k] for k in self.creative_type_allowed_fields[creative['creative_type']] if k in creative} ad_group_setup_block.add_creative(**creative_upload_dict) ad_group_setup_block.add_ad_group(**ad_group) ad_group_setup_blocks.append(ad_group_setup_block) launch_block = WFSocialLaunchBlock() launch_block.provider = self._provider project_blocks = [ order_review_block, data_block, setup_block ] project_blocks.extend(ad_group_setup_blocks) project_blocks.append(launch_block) [project.append(block) for block in project_blocks] parser = WFBlockParser(self.wf) wf_project = parser.create(project) return wf_project
def set_kwargs(obj, kwargs, exclude=[]): """If the argument exists in the object, it is set to the value in the kwargs dict. Excluded values are ignored. """ for k, v in kwargs.items(): if k in exclude: continue try: getattr(obj, k) except AttributeError: raise WFBrigeException('Invalid Key: {}'.format(k)) else: setattr(obj, k, v) return obj
def add_suppression_file(self, file_path, suppression_file_type): ''' @param file_path: s3 file path @param supression_type: bridge_id, email, maid, md5, postal ''' if suppression_file_type not in self.SUPPRESSION_FILE_TYPES: m = "Invalid suppression file type {}. Possible values are {}" err = m.format(suppression_file_type, ",".join(self.SUPPRESSION_FILE_TYPES)) raise WFBrigeException(err) kv = { "file_path": file_path, "suppression_file_type": suppression_file_type } self.suppression_files.append(kv) return self
def build(self): """ @summary: Build the WF project. @raise WFBridgeException: if the combination of parameters set in the builder are not compatible (like missing parameters). @return: a WFProject object. """ project = CWPushContainer(self.project_name) # Project project.bridge_order_id = self.bridge_order_id project.order_name = self.order_name project.partner_name = self.partner_name project.industry = self.industry project.html_link = self.html_link project.banner_link = self.banner_link project.start_date = self.start_date project.target_volume = self.target_volume project.overage = self.overage project.geo_target = self.geo_target project.geo_target_state = self.geo_target_state project.deployment_file_link = self.deployment_file_link project.deployment_file_segment = self.deployment_file_segment project.click_tier = self.click_tier project.open_tier = self.open_tier project.cw_tool_link = self.cw_tool_link project.duration = self.duration if self.purl_processing_enabled is not None: if type(self.purl_processing_enabled) == bool: project.purl_processing_enabled = self.purl_processing_enabled else: raise WFBrigeException('PURL Processing Enabled allowed values: True or False') # Block block = CWPushBlock() project.append(block) parser = WFBlockParser(self.wf) wf_project = parser.create(project) return wf_project
def add_creative(self, **kwargs): n_creatives = len(self._creatives) if n_creatives == self.max_creatives: raise WFBrigeException('The maximum number of creatives for a Carousel or Slideshow is {}' .format(n_creatives)) creative = { 's3_uri': kwargs['s3_uri'], 'asset_type': kwargs['asset_type'], 'title': kwargs['title'], 'description': kwargs['description'], 'website_url': kwargs['website_url'], } self.set_parameter(self.create_carousel_slideshow_task_name, 'Social Carousel S3 URI {}'.format(n_creatives + 1), kwargs['s3_uri']) self.set_parameter(self.create_carousel_slideshow_task_name, 'Social S3 Type {}'.format(n_creatives + 1), kwargs['asset_type']) self.set_parameter(self.create_carousel_slideshow_task_name, 'Social Carousel Title {}'.format(n_creatives + 1), kwargs['title']) self.set_parameter(self.create_carousel_slideshow_task_name, 'Social Carousel Description {}'.format(n_creatives + 1), kwargs['description']) self.set_parameter(self.create_carousel_slideshow_task_name, 'Social Carousel URL {}'.format(n_creatives + 1), kwargs['website_url']) self._creatives.append(creative)
def build(self): """ @summary: build the Workfront project. @raise WFBrigeException @return: WFProject object """ if not self.ad_groups: raise WFBrigeException( 'The project does not have any Ad Groups. Please use add_ad_group to add them.' ) project = WFProjectDisplayContainer(self.project_name) project.ttd_audience_id = self._ttd_audience_id project.ttd_campaign_id = self._ttd_campaign_id project.ttd_flight_id = self._ttd_flight_id project.ttd_creative_id = self._ttd_creative_id project.ttd_advertiser_id = self._ttd_advertiser_id project.is_targeted_bonus_media = self._is_targeted_bonus_media project.multiple_ad_groups = self._multiple_ad_groups project.project_type = self._project_type order_review_block = WFDisplayOrderReviewBlock() # Manual data_block = WFDisplayDataBlock() data_block.audience_name = self._audience_name campaign_block = WFDisplayCampaignBlock() campaign_block.start_date_inclusive_utc = self._start_date_inclusive_utc campaign_block.end_date_exclusive_utc = self._end_date_exclusive_utc campaign_block.campaign_name = self._campaign_name campaign_block.campaign_overview = self._campaign_overview campaign_block.partner_cost_percentage_fee = self._partner_cost_percentage_fee campaign_block.availability = self._availability campaign_block.auto_allocator = self._auto_allocator campaign_block.ctv_targeting_and_attribution = self._ctv_targeting_and_attribution campaign_block.pacing_mode = self._pacing_mode campaign_block.partner_cpm_fee_amount = self._partner_cpm_fee_amount campaign_block.partner_cpm_fee_currency = self._partner_cpm_fee_currency campaign_block.partner_cpc_fee_amount = self._partner_cpc_fee_amount campaign_block.partner_cpc_fee_currency = self._partner_cpc_fee_currency campaign_block.max_bid_amount = self._max_bid_amount campaign_block.budget_in_impressions_pre_calc = self._budget_in_impressions_pre_calc campaign_block.daily_target_in_advertiser_currency = self._daily_target_in_advertiser_currency campaign_block.daily_target_in_impressions = self._daily_target_in_impressions ad_group_setup_blocks = [] qa_blocks = [] for ad_group in self.ad_groups: ad_group_setup_block = WFDisplayAdGroupSetupBlock() qa_block = WFDisplayQABlock() for creative in ad_group['creatives']: creative_upload_dict = { k: creative[k] for k in self.creative_upload_params if k in creative } ad_group_setup_block.add_creative(**creative_upload_dict) creative_qa_dict = { k: creative[k] for k in self.creative_qa_params if k in creative } qa_block.add_creative(**creative_qa_dict) ad_group_setup_block.add_ad_group(**ad_group) ad_group_setup_blocks.append(ad_group_setup_block) ad_group.update({ 'start_date_inclusive_utc': self._start_date_inclusive_utc, 'end_date_exclusive_utc': self._end_date_exclusive_utc, 'campaign_name': self._campaign_name, 'campaign_overview': self._campaign_overview, 'partner_cost_percentage_fee': self._partner_cost_percentage_fee, 'availability': self._availability, 'auto_allocator': self._auto_allocator, 'ctv_targeting_and_attribution': self._ctv_targeting_and_attribution, 'pacing_mode': self._pacing_mode, 'partner_cpm_fee_amount': self._partner_cpm_fee_amount, 'partner_cpm_fee_currency': self._partner_cpm_fee_currency, 'partner_cpc_fee_amount': self._partner_cpc_fee_amount, 'partner_cpc_fee_currency': self._partner_cpc_fee_currency, 'max_bid_amount': self._max_bid_amount, 'budget_in_impressions_pre_calc': self._budget_in_impressions_pre_calc, 'daily_target_in_advertiser_currency': self._daily_target_in_advertiser_currency, 'daily_target_in_impressions': self._daily_target_in_impressions, }) qa_block.add_ad_group(**ad_group) qa_blocks.append(qa_block) launch_block = WFDisplayLaunchBlock() # Manual project_blocks = [ order_review_block, data_block, campaign_block, ] project_blocks.extend(ad_group_setup_blocks) project_blocks.extend(qa_blocks) project_blocks.append(launch_block) [project.append(block) for block in project_blocks] parser = WFBlockParser(self.wf) wf_project = parser.create(project) return wf_project
def raise_missing(field_name): m = "{} is required for match and export data projects" raise WFBrigeException(m.format(field_name))
def check_not_none(name, value): if value is None: raise WFBrigeException("{} is required".format(name))
def _check_viability_b2c(self): if self.count_id is None: raise WFBrigeException("{} is required".format("count_id"))
def add_ad_group(self, **kwargs): """ Ad Group allowed kwargs: * ad_group_name * adg_base_bid_amount * ad_group_name * adg_base_bid_amount * adg_description * adg_daily_budget * adg_daily_budget_in_impressions * adg_budget_in_impressions_pre_calc * adg_pacing_mode * adg_auto_allocator_priority * adg_max_bid_amount * adg_frequency_period_in_minutes * adg_frequency_cap * adg_frequency_pricing_slope_cpm * adg_ctr_in_percent * device_type * country * category * ae_excluder * creatives Creative allowed kwargs: * creative_name - required * creative_size - required * image_s3_url - required * clickthrough_url - required * landing_page_url - required * third_party_tags * third_party_impression_tracking_url * third_party_impression_tracking_url2 * third_party_impression_tracking_url3 * securable * availability * third_party_tag * width * height * [Native Params] """ allowed_kwargs = self.ad_group_params creative_kwargs = set(self.creative_upload_params + self.creative_qa_params) ad_group = {} for k, v in kwargs.items(): if k not in allowed_kwargs: raise WFBrigeException('Invalid Key {}'.format(k)) elif k == 'creatives': ad_group['creatives'] = [] for creative in v: ad_group_creative = {} for creative_key, creative_value in creative.items(): if creative_key not in creative_kwargs: raise WFBrigeException( 'Invalid Key {}'.format(creative_key)) ad_group_creative[creative_key] = creative_value ad_group['creatives'].append(ad_group_creative) else: ad_group[k] = v self.ad_groups.append(ad_group)