Source: index.js

import debug from 'debug';
import { Base64 } from 'js-base64';
import { APP_NAME, AUTH_METHODS } from './Common/Constant';
import { cleanseUrl } from './Common/Util';
import SiteAdmin from './XnatAdmin/SiteAdmin';
import SystemAdmin from './XnatAdmin/SystemAdmin';
import UserAdmin from './XnatAdmin/UserAdmin';
import UserAuth from './XnatAdmin/UserAuth';
import PluginAdmin from './XnatAdmin/PluginAdmin';
import UiConfig from './XnatAdmin/UiConfig';
import DicomConfig from './XnatAdmin/DicomConfig';
import OtherService from './XnatAdmin/OtherService';
import Project from './XnatDataMgmt/Project';
import Subject from './XnatDataMgmt/Subject';
import Experiment from './XnatDataMgmt/Experiment';
import Scan from './XnatDataMgmt/Scan';
import ImageAssessor from './XnatDataMgmt/ImageAssessor';
import Resource from './XnatDataMgmt/Resource';
import Archive from './XnatDataMgmt/Archive';
import Search from './XnatDataMgmt/Search';
import DataProcessing from './XnatDataMgmt/DataProcessing';
import Automation from './XnatDataMgmt/Automation';
import Prearchive from './XnatDataMgmt/Prearchive';
import DicomDump from './XnatDataMgmt/DicomDump';
import Workflow from './XnatDataMgmt/Workflow';

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

/**
 * Auth
 * @typedef {Object} Auth
 * @property {} authMethod -
 * @property {string} [username] - Valid XNAT username
 * @property {string} [password] - Valid XNAT password
 * @property {UserAliasTokenObject} [token] - token object
 */
class Auth {
  constructor(username, password, authMethod = AUTH_METHODS.token) {
    this.username = username;
    this.password = password;
    this.authMethod =
      authMethod === AUTH_METHODS.password ? authMethod : AUTH_METHODS.token;
  }
}

/**
 * JsXnat encapsulates the functionality to create various API wrapper objects.
 */
export default class JsXnat {
  /**
   * Intialize the basic paramemters for accessing an XNAT node
   * @param {string} basePath - the XNAT base URL e.g. https://mirrir.wustl.edu
   * @param {string} username - Valid XNAT username
   * @param {string} password - Valid XNAT password
   * @param {string} [authMethod='token'] Auth Method: either password or token
   */
  constructor(basePath, username, password, authMethod = AUTH_METHODS.token) {
    this.basePath = cleanseUrl(basePath);
    this.auth = new Auth(username, password, authMethod);
  }

  async refreshToken() {
    const userAuth = this.getUserAuth();
    const userAliasTokenApi = userAuth.getUserAliasTokenApi();
    this.auth.token = await userAliasTokenApi.issueToken();
  }

  async invalidateToken() {
    if (!this.auth.token) {
      return;
    }
    const credential = await this.__getCredential();
    const userAuth = this.getUserAuth();
    const userAliasTokenApi = userAuth.getUserAliasTokenApi();
    await userAliasTokenApi.invalidateToken(credential[0], credential[1]);
    this.auth.token = undefined;
  }

  async __validateAuth() {}

  async __getCredential(requiredAuthMethod) {
    const { authMethod, username, password, token } = this.auth;
    if (
      requiredAuthMethod === AUTH_METHODS.password ||
      authMethod === AUTH_METHODS.password
    ) {
      return [username, password];
    }

    let shouldBeRefreshed = true;
    if (token) {
      const { enabled, estimatedExpirationTime } = token;
      if (enabled && estimatedExpirationTime > Date.now()) {
        shouldBeRefreshed = false;
      }
    }

    if (shouldBeRefreshed) {
      await this.refreshToken();
    }
    return [this.auth.token.alias, this.auth.token.secret];
  }

  /**
   * Get the authorization header to be included in the HTTP request header. In most cases, you don't need to call this function directly.
   * @returns {string} authorizatio header
   */
  async getAuthorizationHeader(requiredAuthMethod = undefined) {
    const credential = await this.__getCredential(requiredAuthMethod);
    return 'Basic ' + Base64.encode(credential[0] + ':' + credential[1]);
  }

  /**
   * Get the XNAT's version info that the currrent JsXnat object points to
   * @param {boolean} [includesBuildNumber=false] - true if you want a build number along with version number
   * @returns {string} Version info
   */
  async getVersion(includesBuildNumber = false) {
    const buildInfo = await this.getSiteAdmin()
      .getSiteConfigApi()
      .getBuildInfo();
    let version = `version ${buildInfo.version}`;
    if (includesBuildNumber) {
      version += `, build: ${buildInfo.buildNumber}`;
    }
    return version;
  }

  /**
   * Get the Site Administration group class
   * @returns {SiteAdmin} a Class grouping the API wrappers related to Site-Administration jobs
   */
  getSiteAdmin() {
    return new SiteAdmin(this);
  }

  /**
   * Get the System Administration group class
   * @returns {SystemAdmin} a Class grouping the API wrappers related to System-Administration jobs
   */
  getSystemAdmin() {
    return new SystemAdmin(this);
  }

  /**
   * Get the User Administration group class
   * @returns {UserAdmin} a Class grouping the API wrappers related to User-Administration jobs
   */
  getUserAdmin() {
    return new UserAdmin(this);
  }

  /**
   * Get the User Authentication group class
   * @returns {UserAuth} a Class grouping the API wrappers related to User-Authentication jobs
   */
  getUserAuth() {
    return new UserAuth(this);
  }

  /**
   * Get the Plugin Administration group class
   * @returns {PluginAdmin} a Class grouping the API wrappers related to Plugin-Administration jobs
   */
  getPluginAdmin() {
    return new PluginAdmin(this);
  }

  /**
   * Get the UI Configuration group class
   * @returns {UserAdmin} a Class grouping the API wrappers related to UI-Configuration jobs
   */
  getUiConfig() {
    return new UiConfig(this);
  }

  /**
   * Get the Dicom group class
   * @returns {Dicom} a Class grouping the API wrappers related to DICOM jobs
   */
  getDicomConfig() {
    return new DicomConfig(this);
  }

  /**
   * Get the Other group class
   * @returns {Other} a Class grouping the API wrappers related to miscellaneous jobs
   */
  getOtherService() {
    return new OtherService(this);
  }

  /**
   * Get the Project API wrapper class
   * @returns {Project} the Project API wrapper class
   */
  getProjectApi() {
    return new Project(this);
  }

  /**
   * Get the Subject API wrapper class
   * @returns {Subject} the Subject API wrapper class
   */
  getSubjectApi() {
    return new Subject(this);
  }

  /**
   * Get the Experiment API wrapper class
   * @returns {Experiment} the Experiment API wrapper class
   */
  getExperimentApi() {
    return new Experiment(this);
  }

  /**
   * Get the Scan API wrapper class
   * @returns {Scan} the Scan API wrapper class
   */
  getScanApi() {
    return new Scan(this);
  }

  /**
   * Get the Image Assessor API wrapper class
   * @returns {ImageAssessor} the Image Assessor API wrapper class
   */
  getImageAssessorApi() {
    return new ImageAssessor(this);
  }

  /**
   * Get the Resource API wrapper class
   * @returns {Resource} the Resource API wrapper class
   */
  getResouceApi() {
    return new Resource(this);
  }

  /**
   * Get the Project API wrapper class
   * @returns {Archive} the Archive API wrapper class
   */
  getArchiveApi() {
    return new Archive(this);
  }

  /**
   * Get the Prearchive API wrapper class
   * @returns {Prearchive} the Prearchive API wrapper class
   */
  getPrearchiveApi() {
    return new Prearchive(this);
  }

  /**
   * Get the Search API wrapper class
   * @returns {Search} the Search API wrapper class
   */
  getSearchApi() {
    return new Search(this);
  }

  /**
   * Get the Data Processing API wrapper class
   * @returns {DataProcessing} the Data Processing API wrapper class
   */
  getDataProcessingApi() {
    return new DataProcessing(this);
  }

  /**
   * Get the Automation API wrapper class
   * @returns {Automation} the Automation API wrapper class
   */
  getAutomationApi() {
    return new Automation(this);
  }

  /**
   * Get the Dicom Dump API wrapper class
   * @returns {DicomDump} the Dicom Dump API wrapper class
   */
  getDicomDumpApi() {
    return new DicomDump(this);
  }

  /**
   * Get the Workflow API wrapper class
   * @returns {DicomDump} the Dicom Dump API wrapper class
   */
  getWorkflowApi() {
    return new Workflow(this);
  }
}