File

libs/ngx-pfe/pfe-util/services/util.service.ts

Description

The following parameters can be used in the URL to control certain functionalities of the application.

Index

Properties

Properties

Static Readonly APPLICATION_ID
Type : string
Default value : 'applicationId'

The applicationId is used by the config service to determine the configuration to load. Usually, this corresponds to the branch in the configuration repository.

Static Readonly STATE_ID
Type : string
Default value : 'stateId'

Restore a previously saved state with a specific ID. Usually, the state service will handle this.

Static Readonly TENANT
Type : string
Default value : 'tenant'

The tenant determines the sbp-plugin, where the gateway will forward the calls to.

import { NgxLoggerService } from '@allianz/ngx-logger';
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import jsonpath from 'jsonpath';
import { Subject } from 'rxjs';
import { tap } from 'rxjs/operators';
import { NGX_PFE_CONFIGURATION, NgxPfeModuleConfiguration } from '../../models/ngx-pfe-module-configuration.model';
import { PfeUserInputState } from '../../models/pfe-state/user-input-state.model';
import { TrackingEvent } from '../../models/tracking.model';
import { UnknownObject } from '../../models/unknown-object.model';
import { clone } from '../../util/clone';

/**
 * The RegExp to find JSONPath Expressions in URL
 * Math {$.anything} or {$['anything']}
 */
export const URL_STATE_REGEX = /{\$[^}]*}/gi;

export const STATE_EXPRESSION = '$';

export const ARRAY_STATE_EXPRESSION = '[]$';

/**
 * The following parameters can be used in the URL to control
 * certain functionalities of the application.
 *
 * @export
 */
export class PfeUrlParameters {
  /**
   * The applicationId is used by the config service to determine the configuration to load.
   * Usually, this corresponds to the branch in the configuration repository.
   */
  public static readonly APPLICATION_ID = 'applicationId';
  /**
   * The tenant determines the sbp-plugin, where the gateway will forward the calls to.
   */
  public static readonly TENANT = 'tenant';
  /**
   * Restore a previously saved state with a specific ID.
   * Usually, the state service will handle this.
   */
  public static readonly STATE_ID = 'stateId';
}

@Injectable()
export class PfeUtilService {
  /**
   * This subject is used as a bridge to the tracking integration in @allianz/ngx-pfe/tracking.
   * Events that are triggered here, are forwarded by the PfeTrackingService.
   *
   * As the @allianz/ngx-pfe/tracking integration is optional, a custom integration can also attach to this.
   * (This might be moved to it's own service, if more events are triggered)
   */
  public trackingEvents$ = new Subject<TrackingEvent>();

  public trackingStateRestoredSubject$ = new Subject<PfeUserInputState>();
  /**
   * Triggers when a state is restored, with the restored state as value.
   */
  public trackingStateRestored$ = this.trackingStateRestoredSubject$.asObservable().pipe(tap((value) => clone(value)));

  private _applicationId: string | undefined;
  private _tenant: string | undefined;

  constructor(
    @Inject(NGX_PFE_CONFIGURATION) private ngxPfeModuleConfiguration: NgxPfeModuleConfiguration,
    // @Inject(WINDOW_INJECTION) private window: any
    @Inject(DOCUMENT) private _document: Document,
    private ngxLoggerService: NgxLoggerService
  ) {
    this.readApplicationParameters();
  }

  public get applicationId(): string | undefined {
    if (!this._applicationId) {
      this.readApplicationParameters();
    }
    return this._applicationId;
  }

  public get tenant(): string | undefined {
    if (!this._tenant) {
      this.readApplicationParameters();
    }
    return this._tenant;
  }

  /**
   * Retrieves elements in `obj` that match the jsonpath expression `pathExpression`.
   *
   * Returns the element value if only a single element is found at the path, otherwise
   * a list of matching elements is returned.
   * If you want to receive the result as an array, even if it contains only a single element
   * prepend your pathExpression with '[]' (e.g. '[]$.arrayWithOneElement[0:]')
   *
   * If you want to receive `undefined` in case the result is an empty array, set the optional
   * third parameter to true.
   *
   */
  public static getValueOrList(obj: UnknownObject, pathExpression: string, returnUndefinedForEmptyArray = false) {
    let shouldReturnArray = false;
    if (PfeUtilService.isJsonArrayPathExpression(pathExpression)) {
      shouldReturnArray = true;
      pathExpression = pathExpression.replace(ARRAY_STATE_EXPRESSION, STATE_EXPRESSION);
    }
    const notAJsonPathExpression = !PfeUtilService.isJsonPathExpression(pathExpression);
    if (notAJsonPathExpression) {
      return pathExpression;
    }

    const result = jsonpath.query(obj, pathExpression);

    if (result.length === 0) {
      return undefined;
    }

    if (result.length > 1) {
      return result;
    }

    const onlyResult = result[0];
    const resultIsEmptyArray = Array.isArray(onlyResult) && onlyResult.length === 0;
    if (resultIsEmptyArray && returnUndefinedForEmptyArray) {
      return undefined;
    }
    return shouldReturnArray ? result : onlyResult;
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  public static setValueFromJsonExpression(obj: UnknownObject, pathExpression: string, value: any) {
    if (PfeUtilService.isJsonPathExpression(pathExpression)) {
      jsonpath.value(obj, pathExpression, value);
    }
  }

  /**
   * Check if the pathExpression is a JsonPathExpression
   * Some other services send values that are not really path expressions (like `false` or `true` values)
   * Or some strings that don't start with "$"
   * @param maybeJsonPathExpression Maybe a JsonPathExpression
   * @return true if is a JsonPathExpression
   */
  private static isJsonPathExpression(maybeJsonPathExpression: unknown): boolean {
    return (
      Boolean(maybeJsonPathExpression) && typeof maybeJsonPathExpression == 'string' && maybeJsonPathExpression.startsWith(STATE_EXPRESSION)
    );
  }

  /**
   * Check if the pathExpression is a JsonArrayPathExpression, i.e. starts with '[]$'
   * @param maybeJsonArrayPathExpression Maybe a JsonArrayPathExpression
   * @return true if is a JsonArrayPathExpression
   */
  private static isJsonArrayPathExpression(maybeJsonArrayPathExpression: unknown): boolean {
    return (
      Boolean(maybeJsonArrayPathExpression) &&
      typeof maybeJsonArrayPathExpression == 'string' &&
      maybeJsonArrayPathExpression.startsWith(ARRAY_STATE_EXPRESSION)
    );
  }

  /**
   * Returns a URL parameter, that is either set in the location.search
   * or location.hash.
   */
  public getURLParam(paramName: string): string {
    let paramResult = this.getUrlParams(this._document.location.search, '?')[paramName];
    if (!paramResult) {
      paramResult = this.getUrlParams(this._document.location.hash, '#')[paramName];
    }
    return paramResult ?? '';
  }

  public getUrlParams(search: string, separator: string): Record<string, string> {
    if (!search) {
      return {};
    }
    const hashes = search.slice(search.indexOf(separator) + 1).split('&');
    return hashes.reduce((params, hash) => {
      const [key, val] = hash.split('=');
      return Object.assign(params, { [key]: decodeURIComponent(val ?? '') });
    }, {});
  }

  private readApplicationParameters() {
    this._applicationId = this.getURLParam(PfeUrlParameters.APPLICATION_ID);
    this._tenant = this.getURLParam(PfeUrlParameters.TENANT);
    if (!this._applicationId) {
      this._applicationId = this.ngxPfeModuleConfiguration.applicationId;
    }
    if (!this._tenant) {
      this._tenant = this.ngxPfeModuleConfiguration.tenant;
    }

    if (this._applicationId && this._applicationId !== '') {
      this.ngxLoggerService.debug('Using application: ' + this._applicationId);
    }
    if (this._tenant && this._tenant !== '') {
      this.ngxLoggerService.debug('Using tenant: ' + this._tenant);
    }
  }
}

results matching ""

    No results matching ""