import { AbstractModel } from "./AbstractModel"; import { DDBConnector } from "./connector/DDBConnector"; import logger from "../utils/logger"; import { AdUnitType } from "./app.model"; export type CampaignData = { id: string; economic_type: string; environment_type: string; advertiser?: { id: string; }; priority?: number; apply_appbundle_ssp_whitelist?: boolean; control_list?: { type: string }[]; force_external?: string | boolean; dv_strong_filtering?: string | boolean; without_targetting?: string | boolean; display_as?: string[]; budget?: number; clicks_sold?: number; cpm?: number; ctr?: number; family?: string; prog_deal_id?: string; prog_wseat?: string; prog_bid_floor?: number; prog_dsp_buyer_id?: string; vpaid_tracking?: boolean; margin?: number; creatives?: Creative[]; prebid?: Prebid[]; ad_unit_types?: { [K in string]?: AdUnitConfig; }; }; export type Prebid = { type: string; provider: string; segment?: string; }; export type Creative = { id: number; name: string; format: { id: string; name?: string; ad_type?: string; params?: { [key: string]: any }; }; params?: { [key: string]: any }; }; export type AdUnitConfig = { payback_cpm: number | null; margin: number | null; }; export class CampaignModel extends AbstractModel { constructor(connector: DDBConnector) { super(connector); this.idPrefix = "cm:"; } async findById(id: string | number, suffix: string | null = null) { const data = await super.findById(id, suffix); if (data) { data.id = `${data.id}`; } return data; } static getPrebid(campaign: CampaignData, type: string, provider: string): Prebid[] { return ( campaign?.prebid?.filter((prebid) => prebid.type === type && prebid.provider === provider) ?? [] ); } static hasPrebid(campaign: CampaignData, type: string, provider: string): boolean { return this.getPrebid(campaign, type, provider).length > 0; } isProgrammatic(campaign: CampaignData): boolean { return !!campaign.prog_deal_id; } isMarketplace(campaign: CampaignData): boolean { return campaign.family === "marketplace"; } getPriority(campaign: CampaignData) { return campaign.priority || 2; } isExternalForced(campaign: CampaignData) { return campaign.force_external === true || campaign.force_external === "true"; } isDVStrongFiltering(campaign: CampaignData) { return campaign.dv_strong_filtering === true || campaign.dv_strong_filtering === "true"; } getDisplayAs(campaign: CampaignData): string[] { if (campaign.ad_unit_types) { return Object.keys(campaign.ad_unit_types); } return campaign.display_as as string[]; } getMargin(campaign: CampaignData, ad_unit_type?: string | null): number { let margin: number | null | undefined; if (campaign.ad_unit_types && ad_unit_type) { margin = campaign.ad_unit_types[ad_unit_type]?.margin; } else { // no ad_unit_type in external margin = campaign.margin; } if (margin == null) { logger.error( new Error(`No margin found for campaign ${campaign.id} and ad_unit_type ${ad_unit_type}`) ); return 30; } return margin; } getAdType(campaignData: CampaignData) { let ad_type = "video"; if (campaignData.creatives && campaignData.creatives[0]) { if ( campaignData.creatives[0].format?.ad_type === "video" || campaignData.creatives[0].format?.params?.ad_type === "video" || campaignData.creatives[0].format?.params?.is_video === true ) { ad_type = "video"; } else { ad_type = "display"; } } return ad_type; } getAdAndEcoType(campaign: CampaignData, creativeId: number) { const creative = (campaign.creatives ?? []).find((c) => c.id === creativeId); if (creative) { return { economicType: campaign.economic_type, adType: creative.format?.ad_type, }; } return { economicType: campaign.economic_type, adType: null, }; } isMultiFormatWithThumbnail(campaign: CampaignData) { const display_as = this.getDisplayAs(campaign) || []; const isMultiFormat = display_as.length >= 2; const includeThumbnail = display_as.includes(AdUnitType.overlay_thumbnail); return isMultiFormat && includeThumbnail; } getEnvironmentTypes(campaign: CampaignData) { const environmentType = campaign.environment_type; return environmentType ? environmentType.split(",") : []; } isMultiEnvironmentTypesWithWeb(campaign: CampaignData) { const environmentTypes = this.getEnvironmentTypes(campaign); const isMultiEnvs = environmentTypes.length >= 2; const includeWeb = environmentTypes.includes("web"); return isMultiEnvs && includeWeb; } isMultiEnvironmentsOrMultiFormat(campaign: CampaignData): boolean { const environmentTypes = this.getEnvironmentTypes(campaign); if (environmentTypes.length >= 2) { return true; } const display_as = this.getDisplayAs(campaign) || []; return display_as.length >= 2; } }