Core_Model_DocumentService.js

import { Document } from './Document';

import { RequestService } from '@ud-viz/utils_browser';
import { imageToDataURI } from '@ud-viz/utils_shared';

/**
 * This class is responsible of fetching the documents from the server. It is
 * configured by an object containing the server URL and routes.
 */
export class DocumentService {
  /**
   * Constructs a new document service.
   *
   * @param {RequestService} requestService The request service.
   * @param {object} configServer The server configuration.
   * @param {string} configServer.url The server url.
   * @param {string} configServer.document The base route for documents.
   * @param {string} configServer.file The route for document files.
   * @param {boolean} [configServer.authenticate] If authentication should be
   * used for the request.
   */
  constructor(requestService, configServer) {
    /**
     * The request service.
     *
     * @type {RequestService}
     */
    this.requestService = requestService;

    /**
     * If authentication should be used for the request.
     *
     * @type {boolean}
     */
    this.authenticate = false;
    if (configServer.authenticate) {
      this.authenticate = true;
    }

    /**
     * The object that defines the server URLs to fetch documents.
     *
     * @type {DocumentSource}
     */
    this.source = new DefaultDocumentSource(configServer);

    /**
     * The list of documents.
     *
     * @type {Array<Document>}
     */
    this.documents = [];
  }

  /**
   * Sets the source of documents.
   *
   * @param {DocumentSource} docSource The document source.
   * @param {boolean} [authenticate] Specifies if authentication should be used
   * to fetch documents.
   * @returns {DocumentSource} The previous source.
   */
  setSource(docSource, authenticate = false) {
    if (!(docSource instanceof DocumentSource)) {
      throw 'The document source must be an instance of DocumentSource';
    }

    this.authenticate = authenticate;

    const previous = this.source;
    this.source = docSource;
    return previous;
  }

  /**
   * Fetches the documents from the server and return them in an array.
   *
   * @async
   * @returns {Promise<Array<Document>>} A promise with an array of fetched documents
   */
  async fetchDocuments() {
    const req = await this.requestService.request(
      'GET',
      this.source.getDocumentUrl(),
      { authenticate: this.authenticate }
    );

    if (req.status !== 200) {
      throw 'Could not fetch the documents: ' + req.statusText;
    }

    this.documents = JSON.parse(req.responseText);

    return this.documents;
  }

  /**
   * Fetches the image corresponding to the given document.
   *
   * @param {Document} doc The document to fetch the image.
   * @returns {string} The data string of the image.
   */
  async fetchDocumentImage(doc) {
    const imgUrl = this.source.getImageUrl(doc);
    const req = await this.requestService.request('GET', imgUrl, {
      responseType: 'arraybuffer',
      authenticate: this.authenticate,
    });
    if (req.status >= 200 && req.status < 300) {
      return imageToDataURI(
        req.response,
        req.getResponseHeader('Content-Type')
      );
    }
    throw 'Could not get the file';
  }
}

/**
 * An object that holds and returns the URLs for documents.
 */
export class DocumentSource {
  constructor() {}

  /**
   * Returns the URL to retrieve the documents.
   *
   * @abstract
   * @returns {string} The document URL
   */
  getDocumentUrl() {
    return '';
  }

  /**
   * Returns the URL to retrieve the image of the document.
   *
   * @abstract
   * @returns {string} The image URL
   */
  getImageUrl() {
    return '';
  }
}

/**
 * The default document source, built from the application configuration.
 */
class DefaultDocumentSource extends DocumentSource {
  /**
   *
   * @param {object} configServer The server configuration.
   * @param {string} configServer.url The server url.
   * @param {string} configServer.document The base route for documents.
   * @param {string} configServer.file The route for document files.
   */
  constructor(configServer) {
    super();

    /**
     * The URL to fetch the documents.
     *
     * @type {string}
     */
    this.documentUrl;

    /**
     * The route to fetch the document images.
     *
     * @type {string}
     */
    this.fileRoute;

    if (
      !!configServer &&
      !!configServer.url &&
      !!configServer.document &&
      !!configServer.file
    ) {
      this.documentUrl = configServer.url;
      if (this.documentUrl.slice(-1) !== '/') {
        this.documentUrl += '/';
      }
      this.documentUrl += configServer.document;
      this.fileRoute = configServer.file;
    } else {
      throw 'The given configuration is incorrect.';
    }
  }

  getDocumentUrl() {
    return this.documentUrl;
  }

  /**
   * @override
   * @param {Document} doc The document.
   */
  getImageUrl(doc) {
    return this.documentUrl + '/' + doc.id + '/' + this.fileRoute;
  }
}