All files / src/app/core/identity-provider identity-provider.factory.ts

27.02% Statements 10/37
47.36% Branches 9/19
0% Functions 0/13
28.57% Lines 10/35

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 856x 6x 6x 6x 6x   6x 6x 6x                   6x         6x                                                                                                                          
import { Injectable, InjectionToken, Injector, Type } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { once } from 'lodash-es';
import { noop } from 'rxjs';
import { first } from 'rxjs/operators';
 
import { FeatureToggleService, FeatureToggleType } from 'ish-core/feature-toggle.module';
import { getIdentityProvider } from 'ish-core/store/core/configuration';
import { whenTruthy } from 'ish-core/utils/operators';
 
import { IdentityProvider } from './identity-provider.interface';
 
interface IdentityProviderImplementor {
  type: string;
  implementor: Type<IdentityProvider<unknown>>;
  feature?: FeatureToggleType;
}
 
export const IDENTITY_PROVIDER_IMPLEMENTOR = new InjectionToken<IdentityProviderImplementor>(
  'identityProviderImplementor'
);
 
@Injectable({ providedIn: 'root' })
export class IdentityProviderFactory {
  private instance: IdentityProvider<unknown>;
  private config: {
    [key: string]: unknown;
    type?: string;
  };
 
  constructor(private store: Store, private injector: Injector, private featureToggleService: FeatureToggleService) {
    if (!SSR) {
      this.store.pipe(select(getIdentityProvider), whenTruthy(), first()).subscribe(config => {
        const provider = this.injector
          .get<IdentityProviderImplementor[]>(IDENTITY_PROVIDER_IMPLEMENTOR, [])
          .filter(p => (p.feature ? this.featureToggleService.enabled(p.feature) : true))
          .find(p => p.type === config?.type);
 
        if (!provider) {
          console.error('did not find identity provider for config', config);
        } else {
          const instance = this.injector.get(provider.implementor);
 
          /*
            If the code is called synchronously, the init method can call other actions that can trigger http requests.
            If an HTTP request is triggered before the identity provider constructor is finished, a "Null Pointer Exception" will be thrown in the identity-provider.interceptor.
            A delay with setTimeout is added to mitigate this problem
          */
          // TODO: Find a way to implement this without setTimeout()
          setTimeout(() => {
            instance.init(config);
          }, 1);
 
          this.instance = instance;
          this.config = config;
        }
      });
    } else {
      this.instance = {
        init: noop,
        intercept: (req, next) => next.handle(req),
        triggerLogin: () => true,
        triggerLogout: () => true,
        triggerInvite: () => true,
        getCapabilities: () => ({}),
      };
    }
  }
 
  private logNoIdpError = once(() =>
    console.error('No identity provider instance exists. Please double-check your configuration:', this.config)
  );
 
  getInstance() {
    Iif (!this.instance) {
      this.logNoIdpError();
    }
    return this.instance;
  }
 
  getType(): string {
    return this.config?.type;
  }
}