Lund-Org/cherry

View on GitHub
src/builtins/response.js

Summary

Maintainability
A
0 mins
Test Coverage
const jsonStringify = require('json-stringify-safe')
const check = require('../helpers/check')
const fs = require('../helpers/fs')

/**
 * The method to send the response quickly
 * @param {integer} code The HTTP code of the response
 * @param {object} headers The response headers
 * @param {string} content The content of the response
 */
function response (code, headers, content) {
  headers['Content-Length'] = content.length
  this.writeHead(code, headers)
  this.end(content)
}

/**
 * The default option for the download response
 * @return {Object}
 */
function defaultDownloadOptions () {
  return Object.freeze({
    isFilename: true,
    sourceFilename: null,
    downloadFilename: null,
    headers: {
      'Content-Disposition': 'attachment'
    },
    readFileOptions: 'utf8',
    statusCode: 200
  })
}

/**
 * The default option for the html response
 * @return {Object}
 */
function defaultHTMLOptions () {
  return Object.freeze({
    headers: {
      'Content-Type': 'text/html'
    },
    statusCode: 200,
    isRaw: false,
    parameters: {}
  })
}

/**
 * The default option for the json response
 * @return {Object}
 */
function defaultJSONOptions () {
  return Object.freeze({
    headers: {
      'Content-Type': 'application/json'
    },
    serializer: null,
    indent: 2,
    statusCode: 200
  })
}

/**
 * A method to allow the download of files as response
 * @param {string} ref The path of the file to download or the content already in string
 * @param {object} refOptions The options of the response and the process
 */
async function download (str, refOptions = null) {
  let content = ''
  const options = Object.assign({}, defaultDownloadOptions(), { sourceFilename: str }, refOptions)

  if (!refOptions) {
    options.downloadFilename = str
  } else if (check.isSelfDefinedAndValid(options.isFilename)) {
    if (!options.downloadFilename) {
      options.downloadFilename = options.sourceFilename
    }
  }

  if (check.isSelfDefinedAndValid(options.isFilename)) {
    content = await fs.readFile(options.sourceFilename, options.readFileOptions)
  } else {
    content = str
  }

  if (check.isDefinedAndNotNull(options, 'downloadFilename')) {
    options.headers['Content-Disposition'] += `; filename="${options.downloadFilename}"`
  }

  response.call(this, options.statusCode, options.headers, content)
}

/**
 * A method to render an html response
 * @param {string} str The html or the path to the view
 * @param {object} refOptions The options of the response and the process
 */
async function html (str, refOptions = null) {
  const options = Object.assign({}, defaultHTMLOptions(), refOptions)
  let htmlContent = null
  let viewEngine = null

  if (this.cherry.pluginConfigurator.getPlugin('ViewEngine')) {
    viewEngine = this.cherry.pluginConfigurator.getPluginInstance('ViewEngine')
  }

  if (!viewEngine || options.isRaw) {
    viewEngine = {
      loadTemplate: async (path) => {
        htmlContent = await fs.readFile(path)
      },
      useHtml: (html) => {
        htmlContent = html
      },
      bindTemplate: () => true,
      getRenderedHtml: () => htmlContent
    }
  }

  if (!options.isRaw) {
    await viewEngine.loadTemplate(str)
  } else {
    viewEngine.useHtml(str)
  }
  viewEngine.bindTemplate(options.parameters)
  htmlContent = viewEngine.getRenderedHtml()

  response.call(this, options.statusCode, options.headers, htmlContent)
}

/**
 * Respond a json to the request
 * @param {object|string} ref The entity to stringify or the json already in string
 * @param {object} refOptions The options of the response and the process
 */
function json (ref, refOptions = null) {
  const options = Object.assign({}, defaultJSONOptions(), refOptions)
  let content = ref

  if (typeof ref !== 'string') {
    content = jsonStringify(ref, options.serializer, options.indent)
  }

  response.call(this, options.statusCode, options.headers, content)
}

/**
 * Redirect the user browser
 * @param {string} redirectUri The redirection uri
 * @param {number} redirectionCode The redirection code
 */
function redirect (redirectUri, redirectionCode = 301) {
  const headers = {
    Location: redirectUri
  }
  response.call(this, redirectionCode, headers, '')
}

module.exports = exports = {
  download,
  html,
  json,
  redirect
}

Object.defineProperties(exports, {
  response: {
    value: response
  },
  defaultDownloadOptions: {
    value: defaultDownloadOptions
  },
  defaultHTMLOptions: {
    value: defaultHTMLOptions
  },
  defaultJSONOptions: {
    value: defaultJSONOptions
  }
})