All files / src/properties Properties.ts

98.48% Statements 65/66
74.19% Branches 23/31
100% Functions 10/10
98.41% Lines 62/63

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125            1x 1x       1x         1x     21x     21x         21x   21x 21x 21x 21x 21x 21x   21x 21x 21x     21x 21x 21x 21x 21x 21x         1x 18x 18x 7x 7x 7x   18x               1x 6x 6x 6x 6x 6x 6x     6x 6x 6x 6x 6x 6x     6x     6x     6x 6x     1x 5x     1x   1x     6x 6x 1x 1x         37x 37x 89x 31x     31x   58x 22x       1x  
/*
* Properties.ts
* @author Abhilash Panwar (abpanwar) Hector Hernandez (hectorh)
* @copyright Microsoft 2020
* File containing Properties plugin to collect common properties.
*/
import { BaseTelemetryPlugin, IProcessTelemetryContext, getLocation, Utils, IExtendedTelemetryItem, IEventProperty, CoreUtils } from '@ms/1ds-core-js';
import { _Extensions, _SignalExtKeys, _SharedKeys, _SDKVersion, _emptyString, _UserExtKeys, _MSEI, _ViewEventName, _ActionEventName } from './Constants';
import SessionManager from './SessionManager';
import { IUser } from '../analytics/DataModels';
 
const mseiCookieExpiryDays = 365;
 
/**
 * This class adds a telemetry plugin to populate autocollected properties. 
 */
export default class Properties extends BaseTelemetryPlugin {
  private _timeZone: string;
  private _domain: string;
  private _user: IUser = {};
  private _msei: string;
  private _mseiCreated: boolean;
  private _props:  { [key: string]: string | number | boolean | Date } = {};
  private _sessionManager: SessionManager;
  public origin: string;
 
  constructor() {
    super();
    //Get time zone
    let timeZone = new Date().getTimezoneOffset();
    let minutes = timeZone % 60;
    let hours = (timeZone - minutes) / 60;
    let timeZonePrefix = '+';
    Eif (hours > 0) {
      timeZonePrefix = '-';
    }
    hours = Math.abs(hours);
    minutes = Math.abs(minutes);
    this._timeZone = timeZonePrefix + (hours < 10 ? '0' + hours : hours.toString()) + ':' + (minutes < 10 ? '0' + minutes : minutes.toString());
 
    //Get domain
    let windowLocation = getLocation();
    Eif (windowLocation) {
      let domain = windowLocation.hostname;
      this.origin = windowLocation.origin;
      Eif (domain) {
        this._domain = windowLocation.protocol === 'file:' ? 'local' : domain;
      }
    }
  }
 
  setup(SessionManager: SessionManager) {
    this._msei = Utils.getCookie(_MSEI);
    if (!this._msei) {
      this._msei = Utils.createGuid();
      Utils.setCookie(_MSEI, this._msei, mseiCookieExpiryDays);
      this._mseiCreated = true;
    }
    this._sessionManager = SessionManager;
  }
 
  /**
   * Process the current telemetry item.
   * @param event event to process
   * @param itemCtx context information for the core telemetry library
   */
  processTelemetry(event: IExtendedTelemetryItem, itemCtx?: IProcessTelemetryContext): void {
    event.data[_Extensions._SignalExt][_SignalExtKeys._ExtKey][_SharedKeys._TimeZone] = this._timeZone;
    event.data[_Extensions._SignalExt][_SignalExtKeys._ExtKey][_SharedKeys._Source] = 'Web';
    event.data[_Extensions._SignalExt][_SignalExtKeys._Sdk] = {};
    event.data[_Extensions._SignalExt][_SignalExtKeys._Sdk][_SharedKeys._Version] = _SDKVersion;
    event.data[_Extensions._SignalExt][_SignalExtKeys._Host] = {};
    event.data[_Extensions._SignalExt][_SignalExtKeys._Host][_SharedKeys._Domain] = this._domain;
    
    //Add user fields
    event.data[_Extensions._SignalExt][_SignalExtKeys._User] = {};
    event.data[_Extensions._SignalExt][_SignalExtKeys._User][_UserExtKeys._LocalId] = this._user.localId || this._msei;
    event.data[_Extensions._SignalExt][_SignalExtKeys._User][_UserExtKeys._AuthId] = this._user.authId;
    event.data[_Extensions._SignalExt][_SignalExtKeys._User][_UserExtKeys._AuthType] = this._user.authType;
    event.data[_Extensions._SignalExt][_SignalExtKeys._User][_UserExtKeys._Email] = this._user.email;
    event.data[_Extensions._SignalExt][_SignalExtKeys._User][_SharedKeys._NameKey] = this._user.name;
    
    //Pass event to session manager to process and add required session fields.
    this._sessionManager._processEvent(event, this._mseiCreated, event.name === _ViewEventName || event.name === _ActionEventName);    
    
    //Add common custom properties
    this._addPropsIfNotAlreadyAdded(event.data);
 
    //Delete empty properties
    this._removeEmptyKeys(event.data);
    this.processNext(event, itemCtx);
  }
 
  setUser(user: IUser) {
    this._user = user;
  }
 
  setProperty(name: string, value: string | number | boolean | Date) { 
    //1DS SDK transport will validate name and value so not duplicating it here.     
    this._props[name] = value;    
  }
 
  private _addPropsIfNotAlreadyAdded(data: { [key: string]: string | number | boolean | string[] | number[] | boolean[] | IEventProperty | object}) {
    Utils.arrForEach(Utils.objKeys(this._props), (key) => {
      Eif (!Utils.isValueAssigned(data[key])) {
        data[key] = this._props[key];
      }
    });
  }
 
  private _removeEmptyKeys(input: object) {
    Utils.arrForEach(Utils.objKeys(input), (key) => {
      if (input[key] && Utils.isObject(input[key]) && !CoreUtils.isDate(input[key])) {
        Iif (Utils.objKeys(input[key]).length === 0) {
          delete input[key];
        } else {
          this._removeEmptyKeys(input[key]);
        }
      } else if (!Utils.isValueAssigned(input[key])) {
        delete input[key];
      }
    });
  }
}