File

src/lib/service/backend/backend.service.ts

Description

HttpOptions for http request

Index

Properties

Properties

headers
headers: HttpHeaders | literal type
Type : HttpHeaders | literal type
Optional
observe
observe: any
Type : any
Optional
params
params: HttpParams | literal type
Type : HttpParams | literal type
Optional
reportProgress
reportProgress: boolean
Type : boolean
Optional
responseType
responseType: any
Type : any
Optional
withCredentials
withCredentials: boolean
Type : boolean
Optional

BackendService

BackendService encapsulates the communication with the yuuvis® RAD REST endpoints.

As yuuvis® RAD provides different backend services, this service is also capable of providing the base URIs for those services.

import {of as observableOf, Observable, MonoTypeOperatorFunction} from 'rxjs';
import {map, tap} from 'rxjs/operators';
import {Inject, Injectable} from '@angular/core';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import {Config} from '../config/config.service';
import {DmsObject} from '../../model/dms-object.model';
import * as FileSaver from 'file-saver';
import {Logger} from '../logger/logger';
import {AuthProfile} from '../auth/auth-profile.interface';
import {HttpParams} from '@angular/common/http';
import {finalize, shareReplay} from 'rxjs/operators';
import {CoreConfig} from '../../config/core-config';
import {CORE_CONFIG} from '../../config/core-init.tokens';

/**
 * HttpOptions for http request
 * @param observe: 'body' | 'events' | 'response'
 * @param responseType: 'arraybuffer' | 'blob' | 'json' | 'text'
 */
export interface HttpOptions {
  headers?:
  | HttpHeaders
  | {
    [header: string]: string | string[];
  };
  observe?: any;
  params?:
  | HttpParams
  | {
    [param: string]: string | string[];
  };
  reportProgress?: boolean;
  responseType?: any;
  withCredentials?: boolean;
}


// @ts-ignore
/**
 * `BackendService` encapsulates the communication with the yuuvis<sup>&reg;</sup> RAD REST endpoints.
 *
 * As yuuvis<sup>&reg;</sup> RAD provides different services, this service is also capable of providing the base URIs for those services.
 */
@Injectable({
  providedIn: 'root'
})
export class BackendService {

  public gridDataFilter: MonoTypeOperatorFunction<any> = map((data: any[]) => data?.filter((v: any) => !v.__removed));
  private authProfile: AuthProfile;
  private cache = new Map<string, any>();
  private temp = new Map<string, Observable<any>>();
  private headers = this.setDefaultHeaders();

  /**
   * @ignore
   */
  constructor(private http: HttpClient,
    @Inject(CORE_CONFIG) public coreConfig: CoreConfig,
    private logger: Logger,
    private config: Config) {

    /**
     * default profile is supposed to use NTLM
     * @type {host: string; ntlm: boolean}
     */
    this.authProfile = {
      host: '',
      ntlm: true
    };
  }

  /**
   * @ignore
   */
  public setAuthProfile(profile?: AuthProfile) {
    if (profile) {
      this.headers = this.setDefaultHeaders();
      this.authProfile = profile;
      if (this.authProfile.auth) {
        // this.setHeader('Authorization', this.authProfile.auth);
      }
      this.headers.delete('Authorization');
    }
  }

  /**
   * Add a new header.
   * @param key The headers name
   * @param value The value
   */
  public setHeader(key: string, value: string) {
    if (value && value.length) {
      this.headers = this.headers.set(key, value);
    }
  }

  /**
   * Retrieves the current headers
   * @returns The `HttpHeaders` that are currently set up
   */
  public getHeaders(): HttpHeaders {
    return this.headers;
  }

  /**
   * @ignore
   */
  public getHttpOptions(requestOptions?: HttpOptions): HttpOptions {
    return Object.assign({headers: this.getHeaders(), withCredentials: this.coreConfig.withCredentials}, requestOptions);
  }

  /**
   * Gets the base URI for the DMS-Service endpoint
   * @returns Base URI
   */
  public getServiceBase() {
    return this.config.getUri('serviceBase');
  }

  /**
   * Gets the base URI for the Search-Service endpoint
   * @returns Base URI
   */
  public getSearchBase() {
    return this.config.getUri('searchBase');
  }

  /**
   * Gets the base URI for the Context-Service endpoint
   * @returns Base URI
   */
  public getContextBase() {
    return this.config.getUri('contextBase');
  }

  /**
   * Gets the base URI for the Inbox-Service endpoint
   * @returns Base URI
   */
  public getInboxBase() {
    return this.config.getUri('inboxBase');
  }

  /**
   * Gets the base URI for the BPM-Service endpoint
   * @returns Base URI
   */
  public getBpmBase() {
    return this.config.getUri('bpmBase');
  }

  /**
   * Gets the base URI for the Agent-Service endpoint
   * @returns Base URI
   */
  public getAgentBase() {
    return this.config.getUri('agentBase');
  }

  /**
   * Gets the base URI for the Status-Service endpoint
   * @returns Base URI
   */
  public getStatusBase() {
    return this.config.getUri('statusBase');
  }

  /**
   * @ignore
   */
  public getIconBase(id: string = '') {
    return this.getBaseWithContext(this.getServiceBase()) + '/ui/icon/' + id;
  }

  /**
   * @ignore
   */
  public getHost() {
    return this.authProfile.host || '';
  }

  public getBaseWithContext(base: string) {
    return base?.startsWith('/') ? this.config.getContextPath() + base : base;
  }

  private getContextPath(base?: string): string {
    return this.getHost() + (this.getBaseWithContext(base || this.getServiceBase()));
  }

  /**
   * Wrapped HTTP GET method
   * @param uri The REST URI to be queried
   * @param base The Base URI (backend service) to be used
   * @param requestOptions Additional request options
   * @returns The data retrieved from the given endpoint
   */
  public get(uri: string, base?: string, requestOptions?: HttpOptions): Observable<any> {
    return this.http.get(this.getContextPath(base) + uri, this.getHttpOptions(requestOptions));
  }

  /**
   * Wrapped HTTP PUT method
   * @param uri The target REST URI
   * @param data Data to be 'posted'
   * @param base The Base URI (backend service) to be used
   * @param requestOptions Additional request options
   * @returns The return value of the target PUT endpoint
   */
  public put(uri: string, data?: any, base?: string, requestOptions?: HttpOptions): Observable<any> {
    return this.http.put(this.getContextPath(base) + uri, data, this.getHttpOptions(requestOptions));
  }

  /**
   * @ignore
   */
  public getJson(uri: string, base?: string): Observable<any> {
    return this.http.get(this.getContextPath(base) + uri, this.getHttpOptions({responseType: 'json'}));
  }

  /**
   * Wrapped HTTP POST method
   * @param uri The target REST URI
   * @param data Data to be 'posted'
   * @param base The Base URI (backend service) to be used
   * @param requestOptions Additional request options
   * @returns The return value of the target POST endpoint
   */
  public post(uri: string, data?, base?: string, requestOptions?: HttpOptions): Observable<any> {
    const baseUri = this.getContextPath(base);
    const payload = data ? JSON.stringify(data) : '';
    return this.http.post(`${baseUri}${uri}`, payload, this.getHttpOptions(requestOptions));
  }

  /**
   * Performs a multipart form data POST request.
   * @param uri The target REST URI
   * @param formData FormData to be 'posted'
   * @param base The Base URI (backend service) to be used
   * @param requestOptions Additional request options
   * @returns The return value of the target POST endpoint
   */
  public postMultiPart(uri: string, formData: FormData, base?: string, requestOptions?: HttpOptions): Observable<any> {
    const baseUri = this.getContextPath(base);
    const headers = this.getHeaders();
    headers.delete('Content-Type');
    const reqOptions = Object.assign({headers: headers, withCredentials: this.coreConfig.withCredentials}, requestOptions);
    return this.http.post(`${baseUri}${uri}`, formData, reqOptions);
  }

  /**
   * Wrapped HTTP DELETE method
   * @param uri The target REST URI
   * @param base The Base URI (backend service) to be used
   * @param requestOptions Additional request options
   * @returns The return value of the target DELETE endpoint
   */
  public del(uri: string, base?: string, requestOptions?: HttpOptions): Observable<any> {
    return this.http.delete(this.getContextPath(base) + uri, this.getHttpOptions(requestOptions));
  }

  /**
   * @ignore
   * Soft update for lists - enables grid to handle all changes
   * to add new - only item should be specified
   * to remove - only id should be specified
   * to update - both params should be specified
   *
   * @param any[] list Original list of items
   * @param id?: string; item?: any data[]
   * @returns any[]
   */
  public update(list: any[], data: {id?: string, item?: any}[]) {
    data.forEach(({id, item}) => {
      if (id) {
        const _item = list.find(l => l.id === id);
        Object.assign(_item, item, item ? {__updated: true} : {__removed: true});
      } else if (item) {
        list.unshift(Object.assign(item, {__added: true}));
      }
    });
    return list;
  }

  /**
   * @ignore
   * Cache for small requests like icons and configs
   *
   * @param string uri
   * @returns Observable<any>
   */
  public getViaCache(uri: string): Observable<any> {
    if (this.cache.has(uri)) {
      return observableOf(this.cache.get(uri));
    } else {
      return this.getViaTempCache(uri, () => this.http.get(uri, {withCredentials: this.coreConfig.withCredentials, responseType: 'text'}).pipe(
        tap(text => this.cache.set(uri, text))));
    }
  }

  /**
   * @ignore
   * Temporary Cache for multiple identical requests
   *
   * @param string id
   * @param Function request
   * @returns Observable<any>
   */
  public getViaTempCache(id: string, request?: Function): Observable<any> {
    if (this.temp.has(id)) {
      return this.temp.get(id);
    } else {
      const resp = (request ? request() : this.get(id)).pipe(
        finalize(() => this.temp.delete(id)),
        shareReplay(1)
      );
      this.temp.set(id, resp);
      return resp;
    }
  }

  /**
   * Download the content of dms objects.
   *
   * @param DmsObject[] dmsObjects Array of dms objects to be downloaded
   * @param "PDF" | "TIFF" | "TEXT" | "JPEG" rendition The type of rendition to be downloaded. If not specified, the original content will be downloaded.
   * Possible renditions are `PDF`, `TIFF`, `TEXT`, `JPEG`.
   */
  public downloadContent(dmsObjects: DmsObject[], rendition?: 'PDF' | 'TIFF' | 'TEXT' | 'JPEG', fileNameWithVersionNumber?: boolean, recyclebin?: boolean) {

    const item = dmsObjects[0];
    if (dmsObjects.length === 1) {
      if (item.content) {

        let uri = `/dms/${item.content.id}/content?type=${item.content.type}&asdownload=true&recyclebin=${!!recyclebin}`;
        if (rendition) {
          uri += `&rendition=${rendition}&_intent=DOWNLOAD_${rendition}`;
        } else {
          uri += '&_intent=DOWNLOAD';
        }
        if (item.content.id === item.id) {
          uri += `&version=${item.version}`;
        }
        this.download(uri, fileNameWithVersionNumber ? item.version : null);
      } else {
        this.logger.error('The provided dms object has no content', item);
      }
    }

    if (dmsObjects.length > 1) {
      let uri = '/dms/batch/export';
      if (item.content) {
        const expressions = dmsObjects.map(obj => obj.content.id);
        const data = {
          query: {
            expression: [...expressions]
          },
          options: {
            rendition: ''
          }
        };
        data.options.rendition = rendition ? 'PDF' : null;
        this.downloadMulti(uri, fileNameWithVersionNumber ? item.version : null, data);
      } else {
        this.logger.error('The provided dms object has no content', item);
      }
    }
  }

  public download(uri: string, version?: number) {
    const baseUri = this.getContextPath();
    this.http.get(`${baseUri}${uri}`, {observe: 'response', responseType: 'blob', withCredentials: this.coreConfig.withCredentials})
      .subscribe((res) => {
        FileSaver.saveAs(
          res.body,
          this.getFileNameFromHttpResponse(res, version)
        );
      });
  }

  public downloadMulti(uri: string, version?: number, _body?: any) {
    const baseUri = this.getContextPath();
    this.http.post(`${baseUri}${uri}`, _body, {observe: 'response', responseType: 'blob', withCredentials: this.coreConfig.withCredentials})
      .subscribe((res) => {
        FileSaver.saveAs(
          res.body,
          this.getFileNameFromHttpResponse(res, version)
        );
      });
  }

  private getFileNameFromHttpResponse(res: HttpResponse<any>, version: number) {
    const contentDispositionHeader = res.headers.get('Content-Disposition') || '';
    const encodedFileNameMatchResult = contentDispositionHeader.match('filename\\*=UTF-8\'\'(.*)')
      || contentDispositionHeader.match('filename=\"(.*)\"');
    const encodedFileName = encodedFileNameMatchResult ? encodedFileNameMatchResult[1] : null;
    const filename = encodedFileName ? decodeURIComponent(encodedFileName) : 'unknown';
    const index = !~filename.lastIndexOf('.') ? filename.length : filename.lastIndexOf('.');
    return !version ? filename : `${filename.slice(0, index)}_v${version}${filename.slice(index)}`;
  }


  /**
   * Getter for the HTTP Headers
   *
   * @returns HttpHeaders
   */
  private setDefaultHeaders(): HttpHeaders {
    return new HttpHeaders({
      'Content-Type': 'application/json',
      'X-os-include-links': 'false',
      'X-os-include-actions': 'false',
      'X-os-sync-index': 'true'
    });
  }
}

results matching ""

    No results matching ""