NewTabAttributionFeed.sys.mjs (5233B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 const lazy = {}; 6 7 import { actionTypes as at } from "resource://newtab/common/Actions.mjs"; 8 9 ChromeUtils.defineESModuleGetters(lazy, { 10 newTabAttributionService: 11 "resource://newtab/lib/NewTabAttributionService.sys.mjs", 12 NewTabActorRegistry: "resource://newtab/lib/NewTabActorRegistry.sys.mjs", 13 }); 14 15 const PREF_SYSTEM_ATTRIBUTION = "discoverystream.attribution.enabled"; 16 const PREF_UNIFIED_ADS_SPOCS_ENABLED = "unifiedAds.spocs.enabled"; 17 const PREF_UNIFIED_ADS_TILES_ENABLED = "unifiedAds.tiles.enabled"; 18 // topsites 19 const PREF_FEED_TOPSITES = "feeds.topsites"; 20 const PREF_SYSTEM_TOPSITES = "feeds.system.topsites"; 21 const PREF_SHOW_SPONSORED_TOPSITES = "showSponsoredTopSites"; 22 // spocs 23 const PREF_FEED_SECTION_TOPSTORIES = "feeds.section.topstories"; 24 const PREF_SYSTEM_TOPSTORIES = "feeds.system.topstories"; 25 const PREF_SHOW_SPONSORED = "showSponsored"; 26 const PREF_SYSTEM_SHOW_SPONSORED = "system.showSponsored"; 27 28 /** 29 * - Writes clicks and impressions to NewTabAttributionService. 30 * - Cleared when user history is cleared. 31 */ 32 export class NewTabAttributionFeed { 33 constructor() { 34 this.loaded = false; 35 } 36 37 isEnabled() { 38 const { values } = this.store.getState().Prefs; 39 const systemPref = values[PREF_SYSTEM_ATTRIBUTION]; 40 const experimentVariable = values.trainhopConfig?.attribution?.enabled; 41 42 // Check all shortcuts prefs 43 const tilesEnabled = 44 values[PREF_FEED_TOPSITES] && values[PREF_SYSTEM_TOPSITES]; 45 46 // Check all sponsored shortcuts prefs 47 const sponsoredTilesEnabled = 48 values[PREF_SHOW_SPONSORED_TOPSITES] && 49 values[PREF_UNIFIED_ADS_TILES_ENABLED]; 50 51 // Check all stories prefs 52 const storiesEnabled = 53 values[PREF_FEED_SECTION_TOPSTORIES] && values[PREF_SYSTEM_TOPSTORIES]; 54 55 // Check all sponsored stories prefs 56 const sponsoredStoriesEnabled = 57 values[PREF_UNIFIED_ADS_SPOCS_ENABLED] && 58 values[PREF_SYSTEM_SHOW_SPONSORED] && 59 values[PREF_SHOW_SPONSORED]; 60 61 // Confirm at least one ads section (tiles, spocs) are enabled to allow attribution 62 return ( 63 (systemPref || experimentVariable) && 64 ((tilesEnabled && sponsoredTilesEnabled) || 65 (storiesEnabled && sponsoredStoriesEnabled)) 66 ); 67 } 68 69 async init() { 70 this.loaded = true; 71 lazy.NewTabActorRegistry.registerAttributionActor(); 72 } 73 74 uninit() { 75 this.loaded = false; 76 lazy.NewTabActorRegistry.unregisterAttributionActor(); 77 } 78 79 async onPlacesHistoryCleared() { 80 await lazy.newTabAttributionService.onAttributionReset(); 81 } 82 83 async onPrefChangedAction(action) { 84 switch (action.data.name) { 85 case PREF_SYSTEM_ATTRIBUTION: 86 case "trainhopConfig": 87 case PREF_UNIFIED_ADS_SPOCS_ENABLED: 88 case PREF_UNIFIED_ADS_TILES_ENABLED: 89 case PREF_FEED_TOPSITES: 90 case PREF_SYSTEM_TOPSITES: 91 case PREF_SHOW_SPONSORED_TOPSITES: 92 case PREF_FEED_SECTION_TOPSTORIES: 93 case PREF_SYSTEM_TOPSTORIES: 94 case PREF_SHOW_SPONSORED: 95 case PREF_SYSTEM_SHOW_SPONSORED: { 96 const enabled = this.isEnabled(); 97 98 if (enabled && !this.loaded) { 99 await this.init(); 100 } else if (!enabled && this.loaded) { 101 await this.onPlacesHistoryCleared(); 102 this.uninit(); 103 } 104 break; 105 } 106 } 107 } 108 109 async onAction(action) { 110 switch (action.type) { 111 case at.INIT: 112 if (this.isEnabled() && !this.loaded) { 113 await this.init(); 114 } 115 break; 116 case at.UNINIT: 117 this.uninit(); 118 break; 119 case at.PLACES_HISTORY_CLEARED: 120 await this.onPlacesHistoryCleared(); 121 break; 122 case at.TOP_SITES_SPONSORED_IMPRESSION_STATS: 123 if (this.loaded && this.isEnabled()) { 124 const item = action?.data || {}; 125 if (item.attribution) { 126 if (item.type === "impression") { 127 await lazy.newTabAttributionService.onAttributionEvent( 128 "view", 129 item.attribution 130 ); 131 } else if (item.type === "click") { 132 await lazy.newTabAttributionService.onAttributionEvent( 133 "click", 134 item.attribution 135 ); 136 } 137 } 138 } 139 break; 140 case at.DISCOVERY_STREAM_IMPRESSION_STATS: 141 if (this.loaded && this.isEnabled()) { 142 const item = action?.data?.tiles?.[0] || {}; 143 if (item.attribution) { 144 await lazy.newTabAttributionService.onAttributionEvent( 145 "view", 146 item.attribution 147 ); 148 } 149 } 150 break; 151 case at.DISCOVERY_STREAM_USER_EVENT: 152 if (this.loaded && this.isEnabled()) { 153 const item = action?.data?.value || {}; 154 if (item.attribution) { 155 await lazy.newTabAttributionService.onAttributionEvent( 156 "click", 157 item.attribution 158 ); 159 } 160 } 161 break; 162 case at.PREF_CHANGED: 163 await this.onPrefChangedAction(action); 164 break; 165 } 166 } 167 }