Source: XnatDataMgmt/Resource.js

import queryString from 'query-string';
import debug from 'debug';
import { APP_NAME, RESPONSE_FORMAT, CONTENT_TYPES } from '../Common/Constant';
import Requestable from '../Common/Requestable';
import { IllegalArgumentsError, UnsafeError } from '../Error';

const log = debug(`${APP_NAME}:Resource`);

/**
 * Resource related API
 */
export default class Resource extends Requestable {
  /**
   * Constructor
   * @param {JsXnat} jsXnat
   */
  constructor(jsXnat) {
    super(jsXnat);
  }
  /**
   * creates and returns an Resource object that has the exact same auth and apibase parmeter as the object provided
   * @param {Requestable} any object that extends Requestable
   * @returns {Resorce} new resource object
   */
  static createResource(entity) {
    const { __auth, __apiBase } = entity;
    return new Resource(__auth, __apiBase);
  }

  /**
   * Get A Listing Of Resource Folders
   * @param {string} path the path of the entitiy for the resource (the path of Project, Subject, Image Assessor, or Scan)
   * @param {array | string} sortBy Optional. Sort the returned results by one or more parameters in the Result array. Multiple parameters can be provided
   * @param {string} format Optional. Set the format of the response. Format value can be json, html, xml, or csv. If not specified, default is JSON
   * @param {function} cb optional callback function
   */
  getFolders(path, sortBy = [], format = RESPONSE_FORMAT.json, cb = undefined) {
    if (!sortBy) {
      sortBy = [];
    }
    if (!Array.isArray(sortBy)) {
      sortBy = sortBy.split(',');
    }
    if (!RESPONSE_FORMAT[format]) {
      format = RESPONSE_FORMAT.json;
    }
    return this._request(
      'GET',
      `${path}/resources`,
      {
        sortBy: sortBy.join(','),
        format,
      },
      cb
    );
  }

  /**
   * Get A Listing Of Resource Files Stored With A Entity specifed in the path parameter
   * @param {string} path the path of the entitiy for the resource (the path of Project, Subject, Image Assessor, or Scan)
   * @param {array | string} sortBy Optional. Sort the returned results by one or more parameters in the Result array. Multiple parameters can be provided
   * @param {string} format Optional. Set the format of the response. Format value can be json, html, xml, or csv. If not specified, default is JSON
   * @param {function} cb optional callback function
   */
  getFiles(path, sortBy = [], format = RESPONSE_FORMAT.json, cb = undefined) {
    if (!sortBy) {
      sortBy = [];
    }
    if (!Array.isArray(sortBy)) {
      sortBy = sortBy.split(',');
    }
    if (!RESPONSE_FORMAT[format]) {
      format = RESPONSE_FORMAT.json;
    }
    return this._request(
      'GET',
      `${path}/files`,
      {
        sortBy: sortBy.join(','),
        format,
      },
      cb
    );
  }

  /**
   * Get A Listing Of Resource Files Stored With A Entity specifed in the path parameter
   * @param {string} path the path of the entitiy for the resource (the path of Project, Subject, Image Assessor, or Scan)
   * @param {string} resourceIdOrLabel resource id or label (folder name)
   * @param {string} filename filename
   * @param {function} cb optional callback function
   */
  getFile(path, resourceIdOrLabel, filename, cb = undefined) {
    return this._request(
      'GET',
      `${path}/resources/${resourceIdOrLabel}/files/${filename}`,
      undefined,
      cb
    );
  }

  /**
   * Create A New Resource Folder
   * @param {string} path the path of the entitiy for the resource (the path of Project, Subject, Image Assessor, or Scan)
   * @param {string} resourceLabel resource label (folder name)
   * @param {string} format Optional. Specify a string format descriptor for this resource folder.
   * @param {string | array} tags Optional. Specify a comma-separated list of tags for this resource folder.
   * @param {string} contents Optional. Specify a string description of the resource folder's content.
   * @param {function} cb optional callback function
   * @returns none
   */
  createFolder(
    path,
    resourceLabel,
    format = undefined,
    tags = [],
    content = undefined,
    cb = undefined
  ) {
    if (!resourceLabel) {
      throw new IllegalArgumentsError('resource label is required');
    }
    if (tags && !Array.isArray(tags)) {
      tags = tags.split(',');
    }
    const options = queryString.stringify({
      format,
      tags: tags ? tags.join(',') : undefined,
      content,
    });
    return this._request(
      'PUT',
      `${path}/resources/${resourceLabel}?${options}`,
      undefined,
      cb
    );
  }

  /**
   * Upload A New Resource File
   * @param {string} path the path of the entitiy for the resource (the path of Project, Subject, Image Assessor, or Scan)
   * @param {string} resourceIdOrLabel resource id or label
   * @param {string} filename filename
   * @param {Buffer} file file buffer (need to check if this is compatilable from browser)
   * @param {boolean} overwrite Optional. overwrite the file if the file that has the same filename already exists in the same location
   * @param {function} cb optional callback function
   * @returns none
   */
  uploadFile(
    path,
    resourceIdOrLabel,
    filename,
    file,
    overwrite = false,
    cb = undefined
  ) {
    if (!resourceIdOrLabel) {
      throw new IllegalArgumentsError('resource id or label is required');
    }
    if (!filename) {
      throw new IllegalArgumentsError('filename is required');
    }
    if (!file) {
      throw new IllegalArgumentsError('file is required');
    }
    return this._request(
      'PUT',
      `${path}/resources/${resourceIdOrLabel}/files/${filename}${
        overwrite === true ? '?overwrite=true' : ''
      }`,
      file,
      cb,
      CONTENT_TYPES.binary
    );
  }

  /**
   * Delete A Resource Folder
   * @param {string} path the path of the entitiy for the resource (the path of Project, Subject, Image Assessor, or Scan)
   * @param {string} resourceIdOrLabel resource id or label
   * @param {boolean} safe Optional. if throw errors if files exists in the resource folder
   * @param {function} cb optional callback function
   * @returns none
   */
  async deleteFolder(path, resourceIdOrLabel, safe = false, cb = undefined) {
    if (!resourceIdOrLabel) {
      throw new IllegalArgumentsError('resource id or label is required');
    }
    if (safe) {
      log('#@$#%3454354325432543253255343');
      const {
        ResultSet: { Result: res },
      } = await this.getFolders(path);

      const found = res.find(
        (item) =>
          item.label === resourceIdOrLabel ||
          item.xnat_abstractresource_id === resourceIdOrLabel
      );
      if (found && found.file_count > 0) {
        throw new UnsafeError('the specified folder contains files');
      }
    }
    return this._request(
      'DELETE',
      `${path}/resources/${resourceIdOrLabel}`,
      undefined,
      cb
    );
  }

  /**
   * Delete A Resource File
   * @param {string} path the path of the entitiy for the resource (the path of Project, Subject, Image Assessor, or Scan)
   * @param {string} resourceIdOrLabel resource id or label
   * @param {string} filename filename
   * @param {function} cb optional callback function
   * @returns none
   */
  deleteFile(path, resourceIdOrLabel, filename, cb = undefined) {
    if (!resourceIdOrLabel) {
      throw new IllegalArgumentsError('resource id or label is required');
    }
    if (!filename) {
      throw new IllegalArgumentsError('filename is required');
    }
    return this._request(
      'DELETE',
      `${path}/resources/${resourceIdOrLabel}/files/${filename}`,
      undefined,
      cb
    );
  }
}