File

src/lib/fs/cms/page/fs-cms-page.preparer.ts

Description

This converter prepares FirstSpirit media input components and dataset references for further processing.

Index

Properties
Methods

Constructor

constructor(caasClientFactory: CaasClientFactory, fsSpartacusBridgeConfig: FsSpartacusBridgeConfig, baseSiteService: BaseSiteService)
Parameters :
Name Type Optional
caasClientFactory CaasClientFactory No
fsSpartacusBridgeConfig FsSpartacusBridgeConfig No
baseSiteService BaseSiteService No

Methods

Private addIdentifier2FallbackObjectMapEntry
addIdentifier2FallbackObjectMapEntry(identifier: string, content: any)
Parameters :
Name Type Optional
identifier string No
content any No
Returns : void
Private addIdentifier2ObjectMapEntry
addIdentifier2ObjectMapEntry(identifier: string, content: any)
Parameters :
Name Type Optional
identifier string No
content any No
Returns : void
Private collectDatasetInputComponents
collectDatasetInputComponents(element: Value, addIdentifier2Map: (identifier: string,content: any) => void)
Parameters :
Name Type Optional
element Value No
addIdentifier2Map function No
Returns : boolean
Private collectMediaInputComponents
collectMediaInputComponents(formData: literal type, addIdentifier2Map: (identifier: string,content: any) => void)
Parameters :
Name Type Optional
formData literal type No
addIdentifier2Map function No
Returns : void
convert
convert(source: FsCmsPageInterface | null | undefined)
Parameters :
Name Type Optional
source FsCmsPageInterface | null | undefined No
Returns : Observable<FsCmsPageInterface>
Private deepSearchForDatasetInputComponents
deepSearchForDatasetInputComponents(element: Value, addIdentifier2Map: (identifier: string,content: any) => void)
Parameters :
Name Type Optional
element Value No
addIdentifier2Map function No
Returns : void
Private enhanceSourceItem
enhanceSourceItem(identifier: string, mediaDocument: any)
Parameters :
Name Type Optional
identifier string No
mediaDocument any No
Returns : void
Private getLocalizedMediaIdentifiers
getLocalizedMediaIdentifiers()
Returns : any
Private getLocalizedMediaIdentifiersForFallbackLanguage
getLocalizedMediaIdentifiersForFallbackLanguage()
Returns : any
Private performBulkRequest
performBulkRequest(caasClientObservable: Observable<CaasClient>)
Parameters :
Name Type Optional
caasClientObservable Observable<CaasClient> No
Returns : Observable<any>
Private searchForDatasetReference
searchForDatasetReference(formData: literal type, addIdentifier2Map: (identifier: string,content: any) => void)
Parameters :
Name Type Optional
formData literal type No
addIdentifier2Map function No
Returns : void
Private setSource
setSource(source: FsCmsPageInterface)
Parameters :
Name Type Optional
source FsCmsPageInterface No
Returns : void

Properties

Private fallbackLocale
Type : string
Private identifier2FallbackObjectMap
Type : Map<string | any[]>
Private identifier2ObjectMap
Type : Map<string | any[]>
Private source
Type : FsCmsPageInterface
import { Injectable } from '@angular/core';
import { BaseSiteService, Converter } from '@spartacus/core';

import { FsCmsPageInterface, FormData, Value } from './fs-cms-page.interface';
import { map, filter, take, switchAll, first } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { CaasClientFactory } from '../../caas/caas-client.factory';
import { CaasClient } from '../../caas/caas-client';
import { bind, findDocumentsInCaasResponse } from '../../util/helper';
import { FsSpartacusBridgeConfig } from 'fs-spartacus-common';

/**
 * This converter prepares FirstSpirit media input components and dataset references for further processing.
 *
 * @export
 * @class FsCmsPagePreparer
 */
@Injectable({ providedIn: 'root' })
export class FsCmsPagePreparer implements Converter<FsCmsPageInterface, Observable<FsCmsPageInterface>> {
  private source: FsCmsPageInterface;
  private identifier2ObjectMap: Map<string, any[]>;
  private identifier2FallbackObjectMap: Map<string, any[]>;
  private fallbackLocale: string;
  constructor(
    private caasClientFactory: CaasClientFactory,
    private fsSpartacusBridgeConfig: FsSpartacusBridgeConfig,
    private baseSiteService: BaseSiteService
  ) {}

  convert(source: FsCmsPageInterface | null | undefined): Observable<FsCmsPageInterface> {
    // null is a valid value for source, because it indicates,
    // that a FirstSpirit page is not present, which is a valid state
    if (!source) {
      return of(null);
    }

    let baseSite;
    this.baseSiteService
      .getActive()
      .pipe(first())
      .subscribe((activeBaseSite) => (baseSite = activeBaseSite));
    if (
      this.fsSpartacusBridgeConfig.bridge[baseSite].fallbackLanguage &&
      this.fsSpartacusBridgeConfig.bridge[baseSite].fallbackLanguage !== ''
    ) {
      this.fallbackLocale = this.fsSpartacusBridgeConfig.bridge[baseSite].fallbackLanguage;
    }

    const caasClientFactoryObservable = this.caasClientFactory.createCaasClient().pipe(take(1));
    this.setSource(source);
    if (this.identifier2ObjectMap != null) {
      this.identifier2ObjectMap.clear();
    }
    this.identifier2ObjectMap = new Map();

    if (this.identifier2FallbackObjectMap != null) {
      this.identifier2FallbackObjectMap.clear();
    }
    this.identifier2FallbackObjectMap = new Map();

    for (const children of this.source.page.children) {
      if (children != null) {
        for (const child of children.children) {
          if (this.source.fallbackIdentifiers && this.source.fallbackIdentifiers.includes(child?.identifier)) {
            this.collectMediaInputComponents(child?.formData, bind(this.addIdentifier2FallbackObjectMapEntry, this));
            this.searchForDatasetReference(child?.formData, bind(this.addIdentifier2FallbackObjectMapEntry, this));
          } else {
            this.collectMediaInputComponents(child?.formData, bind(this.addIdentifier2ObjectMapEntry, this));
            this.searchForDatasetReference(child?.formData, bind(this.addIdentifier2ObjectMapEntry, this));
          }
        }
      }
    }
    return this.performBulkRequest(caasClientFactoryObservable);
  }

  private setSource(source: FsCmsPageInterface): void {
    this.source = null;
    this.source = source;
  }

  private addIdentifier2ObjectMapEntry(identifier: string, content: any): void {
    const mapContent = [];
    if (this.identifier2ObjectMap.has(identifier)) {
      mapContent.push(...this.identifier2ObjectMap.get(identifier));
    }
    mapContent.push(content);
    this.identifier2ObjectMap.set(identifier, mapContent);
  }

  private addIdentifier2FallbackObjectMapEntry(identifier: string, content: any): void {
    const mapContent = [];
    if (this.identifier2FallbackObjectMap.has(identifier)) {
      mapContent.push(...this.identifier2FallbackObjectMap.get(identifier));
    }
    mapContent.push(content);
    this.identifier2FallbackObjectMap.set(identifier, mapContent);
  }

  private performBulkRequest(caasClientObservable: Observable<CaasClient>): Observable<any> {
    return caasClientObservable.pipe(
      map((caasClient) =>
        this.identifier2ObjectMap.size > 0 || this.identifier2FallbackObjectMap.size > 0
          ? caasClient.getByIds([...this.getLocalizedMediaIdentifiers(), ...this.getLocalizedMediaIdentifiersForFallbackLanguage()])
          : of(undefined)
      ),
      switchAll(),
      map((caasResponse) => {
        return findDocumentsInCaasResponse(caasResponse);
      }),
      filter((documents) => documents !== undefined),
      map((documents) => {
        documents.forEach((document) => this.enhanceSourceItem(document?.identifier, document));
        delete this.source.fallbackIdentifiers;
        return Object.assign({}, this.source);
      })
    );
  }

  private getLocalizedMediaIdentifiers() {
    // Media files and datasets can be language dependent and independent in FS
    // If the file is language dependent, using the language and country from the top level locale object is correct
    // If the file is language independent, it is correct as well, although the url of a picture in a German CaaS document
    //   will have the locale en_GB, if the master language is English.
    // If the media is called with the de_DE locale, the CaaS will redirect to the en_GB locale (see CAAS-1370).
    return Array.from(this.identifier2ObjectMap.keys()).map((item) => {
      return `'${item}.${this.source.locale.language}_${this.source.locale.country}'`;
    });
  }

  private getLocalizedMediaIdentifiersForFallbackLanguage() {
    return Array.from(this.identifier2FallbackObjectMap.keys()).map((item) => {
      return `'${item}.${this.fallbackLocale}'`;
    });
  }

  private enhanceSourceItem(identifier: string, mediaDocument: any): void {
    if (this.identifier2ObjectMap.has(identifier)) {
      const sourceItems = this.identifier2ObjectMap.get(identifier);
      sourceItems.forEach((sourceItem) => {
        if (sourceItem.fsType === 'Dataset' || sourceItem.fsType === 'DatasetReference') {
          Object.assign(sourceItem, { dataset: mediaDocument });
        } else {
          Object.assign(sourceItem, { resolutions: mediaDocument });
        }
      });
    } else if (this.identifier2FallbackObjectMap.has(identifier)) {
      const sourceItems = this.identifier2FallbackObjectMap.get(identifier);
      sourceItems.forEach((sourceItem) => {
        if (sourceItem.fsType === 'Dataset' || sourceItem.fsType === 'DatasetReference') {
          Object.assign(sourceItem, { dataset: mediaDocument });
        } else {
          Object.assign(sourceItem, { resolutions: mediaDocument });
        }
      });
    }
  }

  private collectMediaInputComponents(
    formData: { [key: string]: FormData },
    addIdentifier2Map: (identifier: string, content: any) => void
  ) {
    Object.values(formData || {})
      .filter(Boolean)
      .forEach((inputComponent) => {
        if (inputComponent.value && typeof inputComponent.value === 'object') {
          if (!Array.isArray(inputComponent.value)) {
            if (inputComponent.value.fsType && inputComponent.value.fsType === 'Media') {
              // Found media without resolution
              addIdentifier2Map(inputComponent.value.identifier, inputComponent.value);
            } else if (inputComponent.value.fsType && inputComponent.value.fsType === 'MappingMedium' && inputComponent.value.media) {
              // Found media inside a MappingMedium providing a resolution
              addIdentifier2Map(inputComponent.value.media.identifier, inputComponent.value.media);
              if (Array.isArray(inputComponent.value.areas)) {
                inputComponent.value.areas
                  .filter((element) => element?.link?.formData)
                  .forEach((element) => {
                    this.collectMediaInputComponents(element.link.formData, addIdentifier2Map);
                  });
              }
            } else if (inputComponent.value.formData) {
              this.collectMediaInputComponents(inputComponent.value.formData, addIdentifier2Map);
            }
          } else {
            inputComponent.value
              .filter((element) => element.formData)
              .forEach((element) => {
                this.collectMediaInputComponents(element.formData, addIdentifier2Map);
              });
          }
        }
      });
  }

  /*
  This method searches for references of datasets.
  (These are not the datasets themselves, but the input components using them)
  When it finds a dataset reference, it writes the identifier of the referenced dataset
  into identifier2ObjectMap for further processing.
   */
  private searchForDatasetReference(formData: { [key: string]: FormData }, addIdentifier2Map: (identifier: string, content: any) => void) {
    Object.values(formData || {}).forEach((inputComponent) => {
      if (inputComponent.value && typeof inputComponent.value === 'object') {
        if (!Array.isArray(inputComponent.value)) {
          this.deepSearchForDatasetInputComponents(inputComponent.value, addIdentifier2Map);
        } else {
          inputComponent.value.forEach((element) => {
            this.deepSearchForDatasetInputComponents(element, addIdentifier2Map);
          });
        }
      }
    });
  }

  private deepSearchForDatasetInputComponents(element: Value, addIdentifier2Map: (identifier: string, content: any) => void) {
    const shouldTerminate = this.collectDatasetInputComponents(element, addIdentifier2Map);
    if (!shouldTerminate && typeof element === 'object') {
      Object.values(element).forEach((elementChild: Value) => {
        if (elementChild) {
          this.deepSearchForDatasetInputComponents(elementChild, addIdentifier2Map);
        }
      });
    }
  }

  private collectDatasetInputComponents(element: Value, addIdentifier2Map: (identifier: string, content: any) => void): boolean {
    if (element.fsType && element.fsType === 'Record' && element.value) {
      addIdentifier2Map(element.value.target.identifier, element.value.target);
      return true;
    } else if (element.fsType && element.fsType === 'DatasetReference') {
      addIdentifier2Map(element.target.identifier, element.target);
      return true;
    } else if (element.formData) {
      return this.collectDatasetInputComponents(element.formData, addIdentifier2Map);
    } else if (element.value && element.value.formData) {
      return this.collectDatasetInputComponents(element.value.formData, addIdentifier2Map);
    }
    return false;
  }
}

results matching ""

    No results matching ""