Home Reference Source

src/controllers/export.controller.js

import Promise from 'bluebird';
import {
  notFound, badImplementation
} from 'boom';
import {
  merge, get, isNull, findIndex, isEqual, nth, identity,
  reduce, isEmpty, map, uniq, union, keys
} from 'lodash';

import Client from '../database/models/client.model';
import Project from '../database/models/project.model';
import EXPORTERS, { getContentType } from '../exporter';

import { projectsListQueryWithClient, projectsListQuery } from '../helpers';

/**
 * This function is a wrapper that selects the right
 * exporter or identity function if none is found
 * @param { Object } locale the locale
 * @param { String } locale.code the locale's code
 * @param { Array } locale.keys the locale's keys
 * @param { String } type the type of export
 * @param { Array } pKeys the project's keys
 * @return { Object | String } The exported data
 */
const _exportLocale = ({ code, keys }, type, pKeys) =>
  get(EXPORTERS, type, identity)(keys, pKeys, code);

/**
 * This function exports the accepted export type
 * @param { Object } request the Hapi request object
 * @param { Function } reply the Hapi reply object
 * @return { Promise } a promise that resolves
 */
export const listExporters = (request, reply) =>
  reply(keys(EXPORTERS));

/**
 * This function exports a project's locale, using the
 * provided type and locale code
 * @param { Object } request the Hapi request object
 * @param { Function } reply the Hapi reply object
 * @return { Promise } a promise that resolves
 */
export const exporterProject = (request, reply) =>
  Project
  .findOne(merge({
    _id: get(request, 'params.id', '')
  }, projectsListQuery(get(request, 'auth.credentials', {}), true)))
  .exec()
  .then((project) => {
    if (isNull(project)) {
      return reply(notFound(new Error('Project not found')));
    }
    const idx = findIndex(get(project, 'locales', []), locale =>
      isEqual(get(locale, 'code', ''), get(request, 'params.locale', '')));

    if (isEqual(idx, -1)) {
      return reply(notFound(new Error('Locale is not in project')));
    }

    return reply(_exportLocale(nth(get(project, 'locales', []), idx),
      get(request, 'params.type', ''), get(project, 'keys', [])))
      .type(getContentType(get(request, 'params.type', '')));
  })
  .catch(err => reply(badImplementation(err)));

/**
 * This function exports some projects' locale, using the
 * provided type and locale code
 * @param { Object } request the Hapi request object
 * @param { Function } reply the Hapi reply object
 * @return { Promise } a promise that resolves
 */
export const exporterProjects = (request, reply) =>
  Promise.all(map(get(request, 'payload.projects', []), _id =>
    Project
    .findOne(projectsListQueryWithClient(get(request,
      'auth.credentials', {}), _id))
    .exec()))
  .then((projects) => {
    if (isEmpty(projects)) {
      return reply(notFound(new Error('Projects not found')));
    }
    const ind = findIndex(projects, project => isNull(project));
    if (!isEqual(ind, -1)) {
      return reply(notFound(new Error(`Project #${nth(get(request, 'payload.projects', []), ind)} does not exists`)));
    }

    const idxs = map(projects, (project) =>
      findIndex(get(project, 'locales', []), locale =>
        isEqual(get(locale, 'code', ''), get(request, 'params.locale', ''))));

    if (!isEqual(findIndex(idxs, idx => isEqual(idx, -1)), -1)) {
      return reply(notFound(new Error('Locale is not in project')));
    }

    return reply(_exportLocale(reduce(projects,
      (total, project, idx) => merge(total, {
        keys: get(nth(get(project, 'locales', []), nth(idxs, idx)), 'keys', {})
      }), {
        code: get(request, 'params.locale', '')
      }), get(request, 'params.type', ''),
      reduce(projects,
        (total, project) => uniq(union(total, get(project, 'keys', []))), [])))
      .type(getContentType(get(request, 'params.type', '')));
  })
  .catch(err => reply(badImplementation(err)));


/**
 * This function exports some projects' locale, using the
 * provided type and locale code
 * @param { Object } request the Hapi request object
 * @param { Function } reply the Hapi reply object
 * @return { Promise } a promise that resolves
 */
export const exporterClientProjects = (request, reply) =>
  Client
  .findById(get(request, 'auth.credentials._id', ''))
  .exec()
  .then((client) => {
    if (isNull(client)) {
      return reply(notFound(new Error('Client does not exists')));
    }

    if (isEmpty(get(client, 'projects', []))) {
      return reply(notFound(new Error('Client does not have any project')));
    }

    return Promise
      .all(map(get(client, 'projects', []), id =>
        Project.findById(id).exec()))
      .then((projects) => {
        if (isEmpty(projects)) {
          return reply(notFound(new Error('Projects not found')));
        }
        const ind = findIndex(projects, project => isNull(project));
        if (!isEqual(ind, -1)) {
          return reply(notFound(new Error(`Project #${ind} does not exists`)));
        }

        const idxs = map(projects, (project) =>
          findIndex(get(project, 'locales', []), locale =>
            isEqual(get(locale, 'code', ''), get(request, 'params.locale', ''))));

        if (!isEqual(findIndex(idxs, idx => isEqual(idx, -1)), -1)) {
          return reply(notFound(new Error('Locale is not in project')));
        }

        return reply(_exportLocale(reduce(projects,
          (total, project, idx) => merge(total, {
            keys: get(nth(get(project, 'locales', []), nth(idxs, idx)), 'keys', {})
          }), {
            code: get(request, 'params.locale', '')
          }), get(request, 'params.type', ''),
          reduce(projects,
            (total, project) => uniq(union(total, get(project, 'keys', []))), [])))
          .type(getContentType(get(request, 'params.type', '')));
      });
  })
  .catch(err => reply(badImplementation(err)));