tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }