<commit_before>/* eslint-env es2018 */
const errors = require('./errors');
const request = require('request');
const { version } = require('../package.json');
const _ = require('lodash');
const generateJwt = require('./generateJwt.js');

/**
* An object representing an OpenTok render.
*
* @property {String} id
*   The ID of the render instance
*
* @property {String} projectId
*   The ID of the project for the render.
*
* @property {String} sessionId
*   The ID of the session being rendered into.
*
* @property {Number} createdAt
*   The time at which the render was created, in milliseconds since the UNIX epoch.
**
* @property {Number} updatedAt
*   The time at which the render was created, in milliseconds since the UNIX epoch.
*
* @property {String} url
*   A publically reachable URL controlled by the customer and capable of generating
*   the content to be rendered without user intervention.
*
* @proerpty {String} status
*   Current status of for the render. Will be one of `started`, `stopped` or `failed`
*
* @property {String} reason
*   Gives a short textual reason for why the Render failed or stopped.
*
* @property {String} callbackUrl
*   URL of the customer service where the callbacks will be received.
*
* @property {String} event
*   Last sent event of for the render
*
* @property {String} resoultion
*   Resolution of the display area for the composition.
*
* @see {@link OpenTok#getRender OpenTok.getRender()}
* @see {@link OpenTok#startRender OpenTok.startRender()}
* @see {@link OpenTok#stopRender OpenTok.stopRender()}
* @see {@link OpenTok#listRenders OpenTok.listRenders()}
*
* @class Render
*/

const generateHeaders = (config, additionalHeaders = {}) => ({
  'User-Agent': 'OpenTok-Node-SDK/' + version,
  'X-OPENTOK-AUTH': generateJwt(config),
  Accept: 'application/json',
  ...additionalHeaders
});

const api = (
  {
    method = 'GET',
    config,
    path,
    params = {},
    body = null,
    headers = {}
  },
  callback
) => {
  const rurl = new URL(config.apiEndpoint);
  rurl.pathname = Array.isArray(path)
    ? _.compact(path).join('/')
    : path;

  rurl.searchParams = params;

  // Increase the likely hood of cache hits
  rurl.searchParams.sort();

  request.defaults(_.pick(config, 'proxy', 'timeout'))(
    {
      url: rurl.href,
      method: method,
      headers: generateHeaders(config, headers),
      json: body
    },
    callback
  );
};

const guardParams = (method, options, callback) => {
  const cb = typeof options === 'function' ? options : callback;
  const opts = typeof options !== 'function' ? options : { count: 50 };

  if (typeof cb !== 'function') {
    throw new errors.ArgumentError('No callback given to ' + method);
  }

  return [cb, opts];
};

const handleResponse = (callback, err, response) => {
  if (err) {
    callback(err);
    return;
  }

  try {
    const { statusCode } = response;

    // TODO use the http-errors package
    switch (statusCode) {
      case 200:
        callback(null, JSON.parse(response.body), response);
        break;
      case 202:
        callback(null, response.body, response);
        break;
      case 401:
      case 403:
        callback(new errors.AuthError(), null, response);
        break;
      case 404:
        callback(new errors.NotFoundError(), null, response);
        break;
      case 500:
        callback(new errors.RequestError(), null, response);
        break;
      default:
        callback(
          new errors.RequestError('Unexpected response code: ' + statusCode),
          null,
          response
        );
    }
  }
  catch (exception) {
    // Most Likely from JSON.parse
    if (exception instanceof SyntaxError) {
      callback(new errors.RequestError('Cannot decode JSON response'));
      return;
    }

    callback(new Error('Uknown Error'));
  }
};

exports.listRenders = (config, options, callback) => {
  const [cb, opts] = guardParams('listRenders', options, callback);
  const { offset, count } = opts;

  if (count > 1000 || count < 1) {
    throw new errors.ArgumentError('Count is out of range');
  }

  const params = new URLSearchParams();

  if (offset) {
    params.append('offset', offset);
  }

  if (count) {
    params.append('count', count);
  }

  api(
    {
      path: 'v2/project/' + config.apiKey + '/render',
      config: config,
      params: params
    },
    _.partial(handleResponse, cb)
  );
};

exports.getRender = (config, renderId, callback) => {
  const [cb] = guardParams('getRender', {}, callback);

  api(
    {
      path: 'v2/project/' + config.apiKey + '/render/' + renderId,
      config: config
    },
    _.partial(handleResponse, cb)
  );
};

exports.startRender = (config, options, callback) => {
  const [cb, opts] = guardParams('startRender', options, callback);

  api(
    {
      method: 'POST',
      path: 'v2/project/' + config.apiKey + '/render',
      config: config,
      body: {
        sessionId: _.get(opts, 'sessionId'),
        token: _.get(opts, 'token'),
        url: _.get(opts, 'url'),
        maxDuration: _.get(opts, 'maxDuration', 1800),
        resolution: _.get(opts, 'resolution', '1280x720'),
        statusCallbackUrl: _.get(opts, 'statusCallbackUrl')
      }
    },
    _.partial(handleResponse, cb)
  );
};

exports.stopRender = (config, renderId, callback) => {
  const [cb] = guardParams('getRender', {}, callback);

  api(
    {
      method: 'DELETE',
      path: 'v2/project/' + config.apiKey + '/render/' + renderId,
      config: config
    },
    _.partial(handleResponse, cb)
  );
};
<commit_msg>docs: update model<commit_after>/* eslint-env es2018 */
const errors = require('./errors');
const request = require('request');
const { version } = require('../package.json');
const _ = require('lodash');
const generateJwt = require('./generateJwt.js');

/**
* An object representing an Experience Composer renderer.
*
* @property {String} id
*   The ID of the render instance
*
* @property {String} projectId
*   The ID of the project for the render.
*
* @property {String} sessionId
*   The ID of the session being rendered into.
*
* @property {Number} createdAt
*   The time at which the render was created, in milliseconds since the UNIX epoch.
**
* @property {Number} updatedAt
*   The time at which the render was created, in milliseconds since the UNIX epoch.
*
* @property {String} url
*   A publically reachable URL controlled by the customer and capable of generating
*   the content to be rendered without user intervention.
*
* @proerpty {String} status
*   Current status of for the render. Will be one of `started`, `stopped` or `failed`
*
* @property {String} reason
*   Gives a short textual reason for why the Render failed or stopped.
*
* @property {String} callbackUrl
*   URL of the customer service where the callbacks will be received.
*
* @property {String} event
*   Last sent event of for the render
*
* @property {String} resoultion
*   Resolution of the display area for the composition.
*
* @see {@link OpenTok#getRender OpenTok.getRender()}
* @see {@link OpenTok#startRender OpenTok.startRender()}
* @see {@link OpenTok#stopRender OpenTok.stopRender()}
* @see {@link OpenTok#listRenders OpenTok.listRenders()}
*
* @class Render
*/

const generateHeaders = (config, additionalHeaders = {}) => ({
  'User-Agent': 'OpenTok-Node-SDK/' + version,
  'X-OPENTOK-AUTH': generateJwt(config),
  Accept: 'application/json',
  ...additionalHeaders
});

const api = (
  {
    method = 'GET',
    config,
    path,
    params = {},
    body = null,
    headers = {}
  },
  callback
) => {
  const rurl = new URL(config.apiEndpoint);
  rurl.pathname = Array.isArray(path)
    ? _.compact(path).join('/')
    : path;

  rurl.searchParams = params;

  // Increase the likely hood of cache hits
  rurl.searchParams.sort();

  request.defaults(_.pick(config, 'proxy', 'timeout'))(
    {
      url: rurl.href,
      method: method,
      headers: generateHeaders(config, headers),
      json: body
    },
    callback
  );
};

const guardParams = (method, options, callback) => {
  const cb = typeof options === 'function' ? options : callback;
  const opts = typeof options !== 'function' ? options : { count: 50 };

  if (typeof cb !== 'function') {
    throw new errors.ArgumentError('No callback given to ' + method);
  }

  return [cb, opts];
};

const handleResponse = (callback, err, response) => {
  if (err) {
    callback(err);
    return;
  }

  try {
    const { statusCode } = response;

    // TODO use the http-errors package
    switch (statusCode) {
      case 200:
        callback(null, JSON.parse(response.body), response);
        break;
      case 202:
        callback(null, response.body, response);
        break;
      case 401:
      case 403:
        callback(new errors.AuthError(), null, response);
        break;
      case 404:
        callback(new errors.NotFoundError(), null, response);
        break;
      case 500:
        callback(new errors.RequestError(), null, response);
        break;
      default:
        callback(
          new errors.RequestError('Unexpected response code: ' + statusCode),
          null,
          response
        );
    }
  }
  catch (exception) {
    // Most Likely from JSON.parse
    if (exception instanceof SyntaxError) {
      callback(new errors.RequestError('Cannot decode JSON response'));
      return;
    }

    callback(new Error('Uknown Error'));
  }
};

exports.listRenders = (config, options, callback) => {
  const [cb, opts] = guardParams('listRenders', options, callback);
  const { offset, count } = opts;

  if (count > 1000 || count < 1) {
    throw new errors.ArgumentError('Count is out of range');
  }

  const params = new URLSearchParams();

  if (offset) {
    params.append('offset', offset);
  }

  if (count) {
    params.append('count', count);
  }

  api(
    {
      path: 'v2/project/' + config.apiKey + '/render',
      config: config,
      params: params
    },
    _.partial(handleResponse, cb)
  );
};

exports.getRender = (config, renderId, callback) => {
  const [cb] = guardParams('getRender', {}, callback);

  api(
    {
      path: 'v2/project/' + config.apiKey + '/render/' + renderId,
      config: config
    },
    _.partial(handleResponse, cb)
  );
};

exports.startRender = (config, options, callback) => {
  const [cb, opts] = guardParams('startRender', options, callback);

  api(
    {
      method: 'POST',
      path: 'v2/project/' + config.apiKey + '/render',
      config: config,
      body: {
        sessionId: _.get(opts, 'sessionId'),
        token: _.get(opts, 'token'),
        url: _.get(opts, 'url'),
        maxDuration: _.get(opts, 'maxDuration', 1800),
        resolution: _.get(opts, 'resolution', '1280x720'),
        statusCallbackUrl: _.get(opts, 'statusCallbackUrl')
      }
    },
    _.partial(handleResponse, cb)
  );
};

exports.stopRender = (config, renderId, callback) => {
  const [cb] = guardParams('getRender', {}, callback);

  api(
    {
      method: 'DELETE',
      path: 'v2/project/' + config.apiKey + '/render/' + renderId,
      config: config
    },
    _.partial(handleResponse, cb)
  );
};
<|endoftext|>


<commit_before>'use strict';

const { capitalize } = require('@metarhia/common');

const LINE_LENGTH = 12;

const lpad = (s, count, char = ' ') => char.repeat(count - s.length) + s;

const line = (title, s) => '\n' + lpad(`${title}: `, LINE_LENGTH) + s;

const renderStack = stack => {
  const path = process.cwd();
  const lines = stack.split('\n');
  const result = lines
    .map(
      (line, i) =>
        ' '.repeat(i ? LINE_LENGTH : 0) +
        line.replace(/at /g, '').replace(path, '')
    )
    .filter(line => !line.includes('(internal/'));
  return result.join('\n');
};

const pad = n => ' '.repeat(n);

class Reporter {
  constructor(options) {
    this.options = Object.assign({}, options);
  }

  record(/* test */) {
    throw new Error('Not implemented');
  }

  error(/* test, error */) {
    throw new Error('Not implemented');
  }

  finish() {
    throw new Error('Not implemented');
  }
}

class ConciseReporter extends Reporter {
  constructor(options) {
    super(options);
    this.successful = 0;
    this.failed = 0;
    this.skipped = 0;
    this.successfulAsserts = 0;
    this.failedAsserts = 0;
  }

  error(test, error) {
    // remove one success because 'error' may only be received after end
    // though the test may have already failed so we need a way to check
    // if we should do this, i.e. store map of successful tests
    // this.successes--;
    // test.todo ? this.skipped++ : this.failures++;
    this.listFailure(
      test,
      { message: `Failure after end: ${error ? error.message : 'no message'}` },
      ` Test failed: ${test.caption}`
    );
  }

  parseTestResults(test, subtest) {
    const testResult = test.success ? 'succeeded' : 'failed';
    const todoPrefix = test.todo ? 'TODO' : '';
    let message = `${todoPrefix} Test ${testResult}: ${test.caption}\n`;
    if (test.metadata.filepath) message += `  ${test.metadata.filepath}\n`;

    if (!test.success && test.output) message += `\nOutput:\n${test.output}\n`;

    let firstFailure = true;
    test.results.forEach(res => {
      if (res.type === 'subtest') {
        const t = res.test;
        if (!t.success) {
          const subResult = {
            type: res.type,
            message: `Subtest ${t.id} / ${t.caption} failed: ${res.message}`,
            success: res.success,
          };
          if (firstFailure) {
            firstFailure = false;
            subtest ? this.printSubtestSeparator() : this.printTestSeparator();
          }
          this.listFailure(t, subResult, message);
        }
        this.parseTestResults(t, true);
      } else if (!res.success) {
        if (res.type !== 'test') this.failedAsserts++;
        if (firstFailure) {
          firstFailure = false;
          subtest ? this.printSubtestSeparator() : this.printTestSeparator();
        }
        this.listFailure(test, res, message);
      } else if (res.type !== 'test') {
        this.successfulAsserts++;
      }
    });
  }

  listFailure(test, res, message) {
    if (res.stack) res.stack = renderStack(res.stack);
    this.printAssertErrorSeparator();
    let s = message;
    ['type', 'message', 'expected', 'actual', 'stack']
      .filter(key => res.hasOwnProperty(key))
      .forEach(key => {
        let value = res[key];
        if (key === 'message' && !value) return;
        if (key === 'actual' || key === 'expected') {
          const isError = value instanceof Error;
          let type = typeof value;
          if (type === 'function' || isError) {
            value = value.toString();
          } else {
            if (type === 'object' && value !== null && value.constructor) {
              type = value.constructor.name;
            }
            if (value === undefined) value = 'undefined';
            else value = JSON.stringify(value, null, 2);
          }
          if (value !== 'undefined' && value !== 'null' && !isError) {
            value += ` is ${type}`;
          }
        }
        s += line(capitalize(key), value);
      });
    console.log(`${s}\n`);
  }

  record(test) {
    if (test.success) this.successful++;
    else if (!test.todo) this.failed++;
    else this.skipped++;
    this.parseTestResults(test);
  }

  finish() {
    this.printTestSeparator();
    console.log(
      'Tests finished: ' +
        `[+${this.successful} | -${this.failed} | ~${this.skipped}]\n` +
        'Asserts:        ' +
        `[+${this.successfulAsserts} | -${this.failedAsserts}]`
    );
  }

  printTestSeparator() {
    console.log('='.repeat(60));
  }

  printSubtestSeparator() {
    console.log('~'.repeat(60));
  }

  printAssertErrorSeparator() {
    console.log('-'.repeat(60));
  }
}

const tapRenderStack = (stack, offset) => {
  const s = stack.replace(/^\s*at /gm, '');
  return '|' + s.slice(s.indexOf('\n')).replace(/\n/g, `\n${pad(offset)}`);
};

const jsonStringifyAndPad = (value, offset) =>
  JSON.stringify(value, null, 2).replace(/\n/g, `\n${pad(offset)}`);

class TapReporter extends Reporter {
  constructor(options) {
    super(options);
    this.successful = 0;
    this.failed = 0;
    this.skipped = 0;
    this.failedTests = [];
    this.testNumeration = 0;
  }

  error(test, error) {
    // remove one success because 'error' may only be received after end
    // though the test may have already failed so we need a way to check
    // if we should do this, i.e. store map of successful tests
    // this.successes--;
    // test.todo ? this.skipped++ : this.failures++;
    // TODO(lundibundi): add test.metadata.filename here too once available
    this.listFailure(
      test,
      { message: `Failure after end: ${error ? error.message : 'no message'}` },
      ` Test failed: ${test.caption}`
    );
  }

  parseTestResults(test, offset = 0) {
    test.results.forEach((res, index) => {
      const testId = index + 1;
      if (res.type === 'subtest') {
        const t = res.test;
        const caption = t.caption || '';
        console.log(`${pad(offset)}# Subtest: ${caption}`);
        this.parseTestResults(t, offset + 4);
        const prefix = t.success ? 'ok' : 'not ok';
        console.log(`${pad(offset)}${prefix} ${testId} - ${caption}`);
      } else if (res.success) {
        console.log(`${pad(offset)}ok ${testId} - ${res.type}`);
      } else {
        console.log(`${pad(offset)}not ok ${testId} - ${res.type}`);
        this.listFailure(res, offset + 2);
      }
    });
    console.log(`${pad(offset)}1..${test.results.length}`);
  }

  listFailure(res, offset) {
    let message = `${pad(offset)}---\n`;
    if (res.message) {
      message += `${pad(offset)}message: '${res.message}'\n`;
    }
    message += `${pad(offset)}severity: `;
    message += res.severity ? `${res.severity}\n` : 'fail\n';
    message += `${pad(offset)}type: ${res.type}\n`;
    const expected = jsonStringifyAndPad(res.expected, offset);
    message += `${pad(offset)}wanted: ${expected}\n`;
    const actual = jsonStringifyAndPad(res.actual, offset);
    message += `${pad(offset)}found: ${actual}\n`;
    const stack = tapRenderStack(res.stack, offset + 2);
    message += `${pad(offset)}stack: ${stack}\n`;
    message += `${pad(offset)}...\n`;
    console.log(message);
    if (
      this.failedTests[this.failedTests.length - 1] !==
      this.testNumeration + 1
    ) {
      this.failedTests.push(this.testNumeration);
    }
  }

  record(test) {
    if (this.testNumeration === 0) console.log('TAP version 13');
    this.testNumeration++;
    if (test.success) {
      this.successful++;
    } else if (!test.todo) {
      this.failed++;
    } else {
      this.skipped++;
    }
    const caption = test.caption || '';
    if (test.todo) {
      console.log(`\nok ${this.testNumeration} - ${caption} # TODO`);
      return;
    }
    console.log(`# Subtest: ${caption}`);
    this.parseTestResults(test, 4);
    const testPrefix = test.success ? 'ok' : 'not ok';
    console.log(`${testPrefix} ${this.testNumeration} - ${caption}`);
  }

  finish() {
    console.log(`1..${this.testNumeration}`);
    if (this.failed !== 0) {
      let testHarness = `FAILED test ${this.failedTests.join(', ')}\n`;
      const percentOfSuccess = (
        ((this.testNumeration - this.failed) / this.testNumeration) *
        100
      ).toFixed(2);
      testHarness += `Failed ${this.failed}/${this.testNumeration} tests, `;
      testHarness += `${percentOfSuccess}% okay`;
      console.log(testHarness);
    }
  }
}

module.exports = {
  Reporter,
  ConciseReporter,
  TapReporter,
};
<commit_msg>Use node util.inspect if available for better test results output<commit_after>'use strict';

const { capitalize } = require('@metarhia/common');

const { inspect } = require('./utils');

const LINE_LENGTH = 12;

const lpad = (s, count, char = ' ') => char.repeat(count - s.length) + s;

const line = (title, s) => '\n' + lpad(`${title}: `, LINE_LENGTH) + s;

const pad = n => ' '.repeat(n);

const renderStack = stack => {
  const path = process.cwd();
  const lines = stack.split('\n');
  const result = lines
    .map(
      (line, i) =>
        ' '.repeat(i ? LINE_LENGTH : 0) +
        line.replace(/at /g, '').replace(path, '')
    )
    .filter(line => !line.includes('(internal/'));
  return result.join('\n');
};

class Reporter {
  constructor(options) {
    this.options = Object.assign({}, options);
  }

  record(/* test */) {
    throw new Error('Not implemented');
  }

  error(/* test, error */) {
    throw new Error('Not implemented');
  }

  finish() {
    throw new Error('Not implemented');
  }
}

class ConciseReporter extends Reporter {
  constructor(options) {
    super(options);
    this.successful = 0;
    this.failed = 0;
    this.skipped = 0;
    this.successfulAsserts = 0;
    this.failedAsserts = 0;
  }

  error(test, error) {
    // remove one success because 'error' may only be received after end
    // though the test may have already failed so we need a way to check
    // if we should do this, i.e. store map of successful tests
    // this.successes--;
    // test.todo ? this.skipped++ : this.failures++;
    this.listFailure(
      test,
      { message: `Failure after end: ${error ? error.message : 'no message'}` },
      ` Test failed: ${test.caption}`
    );
  }

  parseTestResults(test, subtest) {
    const testResult = test.success ? 'succeeded' : 'failed';
    const todoPrefix = test.todo ? 'TODO' : '';
    let message = `${todoPrefix} Test ${testResult}: ${test.caption}\n`;
    if (test.metadata.filepath) message += `  ${test.metadata.filepath}\n`;

    if (!test.success && test.output) message += `\nOutput:\n${test.output}\n`;

    let firstFailure = true;
    test.results.forEach(res => {
      if (res.type === 'subtest') {
        const t = res.test;
        if (!t.success) {
          const subResult = {
            type: res.type,
            message: `Subtest ${t.id} / ${t.caption} failed: ${res.message}`,
            success: res.success,
          };
          if (firstFailure) {
            firstFailure = false;
            subtest ? this.printSubtestSeparator() : this.printTestSeparator();
          }
          this.listFailure(t, subResult, message);
        }
        this.parseTestResults(t, true);
      } else if (!res.success) {
        if (res.type !== 'test') this.failedAsserts++;
        if (firstFailure) {
          firstFailure = false;
          subtest ? this.printSubtestSeparator() : this.printTestSeparator();
        }
        this.listFailure(test, res, message);
      } else if (res.type !== 'test') {
        this.successfulAsserts++;
      }
    });
  }

  listFailure(test, res, message) {
    if (res.stack) res.stack = renderStack(res.stack);
    this.printAssertErrorSeparator();
    let s = message;
    ['type', 'message', 'expected', 'actual', 'stack']
      .filter(key => res.hasOwnProperty(key))
      .forEach(key => {
        let value = res[key];
        if (key === 'message' && !value) return;
        if (key === 'actual' || key === 'expected') {
          const isError = value instanceof Error;
          let type = typeof value;
          if (type === 'function' || isError) {
            value = value.toString();
          } else {
            if (type === 'object' && value !== null && value.constructor) {
              type = value.constructor.name;
            }
            if (value === undefined) value = 'undefined';
            else value = inspect(value);
          }
          if (value !== 'undefined' && value !== 'null' && !isError) {
            value += ` is ${type}`;
          }
        }
        s += line(capitalize(key), value);
      });
    console.log(`${s}\n`);
  }

  record(test) {
    if (test.success) this.successful++;
    else if (!test.todo) this.failed++;
    else this.skipped++;
    this.parseTestResults(test);
  }

  finish() {
    this.printTestSeparator();
    console.log(
      'Tests finished: ' +
        `[+${this.successful} | -${this.failed} | ~${this.skipped}]\n` +
        'Asserts:        ' +
        `[+${this.successfulAsserts} | -${this.failedAsserts}]`
    );
  }

  printTestSeparator() {
    console.log('='.repeat(60));
  }

  printSubtestSeparator() {
    console.log('~'.repeat(60));
  }

  printAssertErrorSeparator() {
    console.log('-'.repeat(60));
  }
}

const tapRenderStack = (stack, offset) => {
  const s = stack.replace(/^\s*at /gm, '');
  return '|' + s.slice(s.indexOf('\n')).replace(/\n/g, `\n${pad(offset)}`);
};

const tapStringifyAndPad = (value, offset) =>
  inspect(value).replace(/\n/g, `\n${pad(offset)}`);

class TapReporter extends Reporter {
  constructor(options) {
    super(options);
    this.successful = 0;
    this.failed = 0;
    this.skipped = 0;
    this.failedTests = [];
    this.testNumeration = 0;
  }

  error(test, error) {
    // remove one success because 'error' may only be received after end
    // though the test may have already failed so we need a way to check
    // if we should do this, i.e. store map of successful tests
    // this.successes--;
    // test.todo ? this.skipped++ : this.failures++;
    // TODO(lundibundi): add test.metadata.filename here too once available
    this.listFailure(
      test,
      { message: `Failure after end: ${error ? error.message : 'no message'}` },
      ` Test failed: ${test.caption}`
    );
  }

  parseTestResults(test, offset = 0) {
    test.results.forEach((res, index) => {
      const testId = index + 1;
      if (res.type === 'subtest') {
        const t = res.test;
        const caption = t.caption || '';
        console.log(`${pad(offset)}# Subtest: ${caption}`);
        this.parseTestResults(t, offset + 4);
        const prefix = t.success ? 'ok' : 'not ok';
        console.log(`${pad(offset)}${prefix} ${testId} - ${caption}`);
      } else if (res.success) {
        console.log(`${pad(offset)}ok ${testId} - ${res.type}`);
      } else {
        console.log(`${pad(offset)}not ok ${testId} - ${res.type}`);
        this.listFailure(res, offset + 2);
      }
    });
    console.log(`${pad(offset)}1..${test.results.length}`);
  }

  listFailure(res, offset) {
    let message = `${pad(offset)}---\n`;
    if (res.message) {
      message += `${pad(offset)}message: '${res.message}'\n`;
    }
    message += `${pad(offset)}severity: `;
    message += res.severity ? `${res.severity}\n` : 'fail\n';
    message += `${pad(offset)}type: ${res.type}\n`;
    const expected = tapStringifyAndPad(res.expected, offset);
    message += `${pad(offset)}wanted: ${expected}\n`;
    const actual = tapStringifyAndPad(res.actual, offset);
    message += `${pad(offset)}found: ${actual}\n`;
    const stack = tapRenderStack(res.stack, offset + 2);
    message += `${pad(offset)}stack: ${stack}\n`;
    message += `${pad(offset)}...\n`;
    console.log(message);
    if (
      this.failedTests[this.failedTests.length - 1] !==
      this.testNumeration + 1
    ) {
      this.failedTests.push(this.testNumeration);
    }
  }

  record(test) {
    if (this.testNumeration === 0) console.log('TAP version 13');
    this.testNumeration++;
    if (test.success) {
      this.successful++;
    } else if (!test.todo) {
      this.failed++;
    } else {
      this.skipped++;
    }
    const caption = test.caption || '';
    if (test.todo) {
      console.log(`\nok ${this.testNumeration} - ${caption} # TODO`);
      return;
    }
    console.log(`# Subtest: ${caption}`);
    this.parseTestResults(test, 4);
    const testPrefix = test.success ? 'ok' : 'not ok';
    console.log(`${testPrefix} ${this.testNumeration} - ${caption}`);
  }

  finish() {
    console.log(`1..${this.testNumeration}`);
    if (this.failed !== 0) {
      let testHarness = `FAILED test ${this.failedTests.join(', ')}\n`;
      const percentOfSuccess = (
        ((this.testNumeration - this.failed) / this.testNumeration) *
        100
      ).toFixed(2);
      testHarness += `Failed ${this.failed}/${this.testNumeration} tests, `;
      testHarness += `${percentOfSuccess}% okay`;
      console.log(testHarness);
    }
  }
}

module.exports = {
  Reporter,
  ConciseReporter,
  TapReporter,
};
<|endoftext|>


<commit_before>import { pick, clone, extend, isEqual, isString } from './dash'
import dsl from './dsl'
import Path from './path'
import invariant from './invariant'
import HistoryLocation from './locations/history'
import MemoryLocation from './locations/memory'
import transition from './transition'
import { intercept } from './links'
import createLogger from './logger'
import qs from './qs'

function Cherrytree () {
  this.initialize.apply(this, arguments)
}

/**
 * The actual constructor
 * @param {Object} options
 */
Cherrytree.prototype.initialize = function (options) {
  this.nextId = 1
  this.state = {}
  this.middleware = []
  this.options = extend({
    location: 'history',
    interceptLinks: true,
    logError: true,
    Promise: Promise,
    qs: qs
  }, options)
  this.log = createLogger(this.options.log)
  this.logError = createLogger(this.options.logError, { error: true })

  invariant(typeof this.options.Promise === 'function',
    'Cherrytree requires an ES6 Promise implementation, ' +
    'either as an explicit option or a global Promise')
}

/**
 * Add a middleware
 * @param  {Function} middleware
 * @return {Object}   router
 * @api public
 */
Cherrytree.prototype.use = function (middleware) {
  this.middleware.push(middleware)
  return this
}

/**
 * Add the route map
 * @param  {Function} routes
 * @return {Object}   router
 * @api public
 */
Cherrytree.prototype.map = function (routes) {
  // create the route tree
  this.routes = dsl(routes)

  // create the matcher list, which is like a flattened
  // list of routes = a list of all branches of the route tree
  let matchers = this.matchers = []
  // keep track of whether duplicate paths have been created,
  // in which case we'll warn the dev
  let dupes = {}

  eachBranch({routes: this.routes}, [], function (routes) {
    // concatenate the paths of the list of routes
    let path = routes.reduce(function (memo, r) {
      // reset if there's a leading slash, otherwise concat
      // and keep resetting the trailing slash
      return (r.path[0] === '/' ? r.path : memo + '/' + r.path).replace(/\/$/, '')
    }, '')
    // ensure we have a leading slash
    if (path === '') {
      path = '/'
    }
    // register routes
    matchers.push({
      routes: routes,
      name: routes[routes.length - 1].name,
      path: path
    })

    // dupe detection
    let lastRoute = routes[routes.length - 1]
    if (dupes[path]) {
      throw new Error('Routes ' + dupes[path] + ' and ' + lastRoute.name +
      ' have the same url path \'' + path + '\'')
    }
    dupes[path] = lastRoute.name
  })

  function eachBranch (node, memo, fn) {
    node.routes.forEach(function (route) {
      if (!route.options || route.options.abstract !== true) {
        fn(memo.concat(route))
      }
      if (route.routes && route.routes.length > 0) {
        eachBranch(route, memo.concat(route), fn)
      }
    })
  }

  return this
}

/**
 * Starts listening to the location changes.
 * @param  {Object}  location (optional)
 * @return {Promise} initial transition
 *
 * @api public
 */
Cherrytree.prototype.listen = function (path) {
  let location = this.location = this.createLocation(path || '')
  // setup the location onChange handler
  location.onChange((url) => this.dispatch(url))
  // start intercepting links
  if (this.options.interceptLinks && location.usesPushState()) {
    this.interceptLinks()
  }
  // and also kick off the initial transition
  return this.dispatch(location.getURL())
}

/**
 * Transition to a different route. Passe in url or a route name followed by params and query
 * @param  {String} url     url or route name
 * @param  {Object} params  Optional
 * @param  {Object} query   Optional
 * @return {Object}         transition
 *
 * @api public
 */
Cherrytree.prototype.transitionTo = function (...args) {
  if (this.state.activeTransition) {
    return this.replaceWith.apply(this, args)
  }
  return this.doTransition('setURL', args)
}

/**
 * Like transitionTo, but doesn't leave an entry in the browser's history,
 * so clicking back will skip this route
 * @param  {String} url     url or route name followed by params and query
 * @param  {Object} params  Optional
 * @param  {Object} query   Optional
 * @return {Object}         transition
 *
 * @api public
 */
Cherrytree.prototype.replaceWith = function (...args) {
  return this.doTransition('replaceURL', args)
}

/**
 * Create an href
 * @param  {String} name   target route name
 * @param  {Object} params
 * @param  {Object} query
 * @return {String}        href
 *
 * @api public
 */
Cherrytree.prototype.generate = function (name, params, query) {
  invariant(this.location, 'call .listen() before using .generate()')
  let matcher

  params = params || {}
  query = query || {}

  this.matchers.forEach(function (m) {
    if (m.name === name) {
      matcher = m
    }
  })

  if (!matcher) {
    throw new Error('No route is named ' + name)
  }

  // this might be a dangerous feature, although it's useful in practise
  // if some params are not passed into the generate call, they're populated
  // based on the current state or on the currently active transition.
  // Consider removing this.. since the users can opt into this behaviour, by
  // reaching out to the router.state if that's what they want.
  let currentParams = clone(this.state.params || {})
  if (this.state.activeTransition) {
    currentParams = clone(this.state.activeTransition.params || {})
  }
  params = extend(currentParams, params)

  let url = Path.withQuery(this.options.qs, Path.injectParams(matcher.path, params), query)
  return this.location.formatURL(url)
}

/**
 * Stop listening to URL changes
 * @api public
 */
Cherrytree.prototype.destroy = function () {
  if (this.location && this.location.destroy && this.location.destroy) {
    this.location.destroy()
  }
  if (this.disposeIntercept) {
    this.disposeIntercept()
  }
  if (this.state.activeTransition) {
    this.state.activeTransition.cancel()
  }
  this.state = {}
}

/**
 * @api private
 */
Cherrytree.prototype.doTransition = function (method, params) {
  let previousUrl = this.location.getURL()

  let url = params[0]
  if (url[0] !== '/') {
    url = this.generate.apply(this, params)
    url = url.replace(/^#/, '/')
  }

  if (this.options.pushState) {
    url = this.location.removeRoot(url)
  }

  let transition = this.dispatch(url)

  transition.catch((err) => {
    if (err && err.type === 'TransitionCancelled') {
      // reset the URL in case the transition has been cancelled
      this.location.replaceURL(previousUrl, {trigger: false})
    }
    return err
  })

  this.location[method](url, {trigger: false})

  return transition
}

/**
 * Match the path against the routes
 * @param  {String} path
 * @return {Object} the list of matching routes and params
 *
 * @api private
 */
Cherrytree.prototype.match = function (path) {
  path = (path || '').replace(/\/$/, '') || '/'
  let found = false
  let params
  let query
  let routes = []
  let pathWithoutQuery = Path.withoutQuery(path)
  let qs = this.options.qs
  this.matchers.forEach(function (matcher) {
    if (!found) {
      params = Path.extractParams(matcher.path, pathWithoutQuery)
      if (params) {
        found = true
        routes = matcher.routes
        query = Path.extractQuery(qs, path) || {}
      }
    }
  })
  return {
    routes: routes.map(descriptor),
    params: params || {},
    query: query || {}
  }

  // clone the data (only a shallow clone of options)
  // to make sure the internal route store is not mutated
  // by the middleware. The middleware can mutate data
  // before it gets passed into the next middleware, but
  // only within the same transition. New transitions
  // will get to use pristine data.
  function descriptor (route) {
    return {
      name: route.name,
      path: route.path,
      params: pick(params, Path.extractParamNames(route.path)),
      options: clone(route.options)
    }
  }
}

Cherrytree.prototype.dispatch = function (path) {
  let match = this.match(path)
  let query = match.query
  let pathname = Path.withoutQuery(path)

  let activeTransition = this.state.activeTransition

  // if we already have an active transition with all the same
  // params - return that and don't do anything else
  if (activeTransition &&
      activeTransition.pathname === pathname &&
      isEqual(activeTransition.query, query)) {
    return activeTransition
  }

  // otherwise, cancel the active transition since we're
  // redirecting (or initiating a brand new transition)
  if (activeTransition) {
    let err = new Error('TransitionRedirected')
    err.type = 'TransitionRedirected'
    err.nextPath = path
    activeTransition.cancel(err)
  }

  // if there is no active transition, check if
  // this is a noop transition, in which case, return
  // a transition to respect the function signature,
  // but don't actually run any of the middleware
  if (!activeTransition) {
    if (this.state.pathname === pathname &&
        isEqual(this.state.query, query)) {
      return transition({
        id: this.nextId++,
        path: path,
        match: match,
        noop: true,
        router: this
      }, this.options.Promise)
    }
  }

  let t = transition({
    id: this.nextId++,
    path: path,
    match: match,
    router: this
  }, this.options.Promise)

  this.state.activeTransition = t

  return t
}

/**
 * Create the default location.
 * This is used when no custom location is passed to
 * the listen call.
 * @return {Object} location
 *
 * @api private
 */
Cherrytree.prototype.createLocation = function (path) {
  let location = this.options.location
  if (!isString(location)) {
    return location
  }
  if (location === 'history') {
    return new HistoryLocation(pick(this.options, ['pushState', 'root']))
  } else if (location === 'memory') {
    return new MemoryLocation({path})
  } else {
    throw new Error('Location can be `history`, `memory` or a custom implementation')
  }
}

/**
 * When using pushState, it's important to setup link interception
 * because all link clicks should be handled via the router instead of
 * browser reloading the page
 */
Cherrytree.prototype.interceptLinks = function () {
  let clickHandler = typeof this.options.interceptLinks === 'function'
    ? this.options.interceptLinks
    : defaultClickHandler
  this.disposeIntercept = intercept((event, link) => clickHandler(event, link, this))

  function defaultClickHandler (event, link, router) {
    event.preventDefault()
    router.transitionTo(router.location.removeRoot(link.getAttribute('href')))
  }
}

export default function cherrytree (options) {
  return new Cherrytree(options)
}
<commit_msg>Move abstract check to a function<commit_after>import { pick, clone, extend, isEqual, isString } from './dash'
import dsl from './dsl'
import Path from './path'
import invariant from './invariant'
import HistoryLocation from './locations/history'
import MemoryLocation from './locations/memory'
import transition from './transition'
import { intercept } from './links'
import createLogger from './logger'
import qs from './qs'

function Cherrytree () {
  this.initialize.apply(this, arguments)
}

/**
 * The actual constructor
 * @param {Object} options
 */
Cherrytree.prototype.initialize = function (options) {
  this.nextId = 1
  this.state = {}
  this.middleware = []
  this.options = extend({
    location: 'history',
    interceptLinks: true,
    logError: true,
    Promise: Promise,
    qs: qs
  }, options)
  this.log = createLogger(this.options.log)
  this.logError = createLogger(this.options.logError, { error: true })

  invariant(typeof this.options.Promise === 'function',
    'Cherrytree requires an ES6 Promise implementation, ' +
    'either as an explicit option or a global Promise')
}

/**
 * Add a middleware
 * @param  {Function} middleware
 * @return {Object}   router
 * @api public
 */
Cherrytree.prototype.use = function (middleware) {
  this.middleware.push(middleware)
  return this
}

/**
 * Add the route map
 * @param  {Function} routes
 * @return {Object}   router
 * @api public
 */
Cherrytree.prototype.map = function (routes) {
  // create the route tree
  this.routes = dsl(routes)

  // create the matcher list, which is like a flattened
  // list of routes = a list of all branches of the route tree
  let matchers = this.matchers = []
  // keep track of whether duplicate paths have been created,
  // in which case we'll warn the dev
  let dupes = {}

  eachBranch({routes: this.routes}, [], function (routes) {
    // concatenate the paths of the list of routes
    let path = routes.reduce(function (memo, r) {
      // reset if there's a leading slash, otherwise concat
      // and keep resetting the trailing slash
      return (r.path[0] === '/' ? r.path : memo + '/' + r.path).replace(/\/$/, '')
    }, '')
    // ensure we have a leading slash
    if (path === '') {
      path = '/'
    }
    // register routes
    matchers.push({
      routes: routes,
      name: routes[routes.length - 1].name,
      path: path
    })

    // dupe detection
    let lastRoute = routes[routes.length - 1]
    if (dupes[path]) {
      throw new Error('Routes ' + dupes[path] + ' and ' + lastRoute.name +
      ' have the same url path \'' + path + '\'')
    }
    dupes[path] = lastRoute.name
  })

  function eachBranch (node, memo, fn) {
    node.routes.forEach(function (route) {
      if (!abstract(route)) {
        fn(memo.concat(route))
      }
      if (route.routes && route.routes.length > 0) {
        eachBranch(route, memo.concat(route), fn)
      }
    })
  }

  function abstract (route) {
    return route.options && route.options.abstract
  }

  return this
}

/**
 * Starts listening to the location changes.
 * @param  {Object}  location (optional)
 * @return {Promise} initial transition
 *
 * @api public
 */
Cherrytree.prototype.listen = function (path) {
  let location = this.location = this.createLocation(path || '')
  // setup the location onChange handler
  location.onChange((url) => this.dispatch(url))
  // start intercepting links
  if (this.options.interceptLinks && location.usesPushState()) {
    this.interceptLinks()
  }
  // and also kick off the initial transition
  return this.dispatch(location.getURL())
}

/**
 * Transition to a different route. Passe in url or a route name followed by params and query
 * @param  {String} url     url or route name
 * @param  {Object} params  Optional
 * @param  {Object} query   Optional
 * @return {Object}         transition
 *
 * @api public
 */
Cherrytree.prototype.transitionTo = function (...args) {
  if (this.state.activeTransition) {
    return this.replaceWith.apply(this, args)
  }
  return this.doTransition('setURL', args)
}

/**
 * Like transitionTo, but doesn't leave an entry in the browser's history,
 * so clicking back will skip this route
 * @param  {String} url     url or route name followed by params and query
 * @param  {Object} params  Optional
 * @param  {Object} query   Optional
 * @return {Object}         transition
 *
 * @api public
 */
Cherrytree.prototype.replaceWith = function (...args) {
  return this.doTransition('replaceURL', args)
}

/**
 * Create an href
 * @param  {String} name   target route name
 * @param  {Object} params
 * @param  {Object} query
 * @return {String}        href
 *
 * @api public
 */
Cherrytree.prototype.generate = function (name, params, query) {
  invariant(this.location, 'call .listen() before using .generate()')
  let matcher

  params = params || {}
  query = query || {}

  this.matchers.forEach(function (m) {
    if (m.name === name) {
      matcher = m
    }
  })

  if (!matcher) {
    throw new Error('No route is named ' + name)
  }

  // this might be a dangerous feature, although it's useful in practise
  // if some params are not passed into the generate call, they're populated
  // based on the current state or on the currently active transition.
  // Consider removing this.. since the users can opt into this behaviour, by
  // reaching out to the router.state if that's what they want.
  let currentParams = clone(this.state.params || {})
  if (this.state.activeTransition) {
    currentParams = clone(this.state.activeTransition.params || {})
  }
  params = extend(currentParams, params)

  let url = Path.withQuery(this.options.qs, Path.injectParams(matcher.path, params), query)
  return this.location.formatURL(url)
}

/**
 * Stop listening to URL changes
 * @api public
 */
Cherrytree.prototype.destroy = function () {
  if (this.location && this.location.destroy && this.location.destroy) {
    this.location.destroy()
  }
  if (this.disposeIntercept) {
    this.disposeIntercept()
  }
  if (this.state.activeTransition) {
    this.state.activeTransition.cancel()
  }
  this.state = {}
}

/**
 * @api private
 */
Cherrytree.prototype.doTransition = function (method, params) {
  let previousUrl = this.location.getURL()

  let url = params[0]
  if (url[0] !== '/') {
    url = this.generate.apply(this, params)
    url = url.replace(/^#/, '/')
  }

  if (this.options.pushState) {
    url = this.location.removeRoot(url)
  }

  let transition = this.dispatch(url)

  transition.catch((err) => {
    if (err && err.type === 'TransitionCancelled') {
      // reset the URL in case the transition has been cancelled
      this.location.replaceURL(previousUrl, {trigger: false})
    }
    return err
  })

  this.location[method](url, {trigger: false})

  return transition
}

/**
 * Match the path against the routes
 * @param  {String} path
 * @return {Object} the list of matching routes and params
 *
 * @api private
 */
Cherrytree.prototype.match = function (path) {
  path = (path || '').replace(/\/$/, '') || '/'
  let found = false
  let params
  let query
  let routes = []
  let pathWithoutQuery = Path.withoutQuery(path)
  let qs = this.options.qs
  this.matchers.forEach(function (matcher) {
    if (!found) {
      params = Path.extractParams(matcher.path, pathWithoutQuery)
      if (params) {
        found = true
        routes = matcher.routes
        query = Path.extractQuery(qs, path) || {}
      }
    }
  })
  return {
    routes: routes.map(descriptor),
    params: params || {},
    query: query || {}
  }

  // clone the data (only a shallow clone of options)
  // to make sure the internal route store is not mutated
  // by the middleware. The middleware can mutate data
  // before it gets passed into the next middleware, but
  // only within the same transition. New transitions
  // will get to use pristine data.
  function descriptor (route) {
    return {
      name: route.name,
      path: route.path,
      params: pick(params, Path.extractParamNames(route.path)),
      options: clone(route.options)
    }
  }
}

Cherrytree.prototype.dispatch = function (path) {
  let match = this.match(path)
  let query = match.query
  let pathname = Path.withoutQuery(path)

  let activeTransition = this.state.activeTransition

  // if we already have an active transition with all the same
  // params - return that and don't do anything else
  if (activeTransition &&
      activeTransition.pathname === pathname &&
      isEqual(activeTransition.query, query)) {
    return activeTransition
  }

  // otherwise, cancel the active transition since we're
  // redirecting (or initiating a brand new transition)
  if (activeTransition) {
    let err = new Error('TransitionRedirected')
    err.type = 'TransitionRedirected'
    err.nextPath = path
    activeTransition.cancel(err)
  }

  // if there is no active transition, check if
  // this is a noop transition, in which case, return
  // a transition to respect the function signature,
  // but don't actually run any of the middleware
  if (!activeTransition) {
    if (this.state.pathname === pathname &&
        isEqual(this.state.query, query)) {
      return transition({
        id: this.nextId++,
        path: path,
        match: match,
        noop: true,
        router: this
      }, this.options.Promise)
    }
  }

  let t = transition({
    id: this.nextId++,
    path: path,
    match: match,
    router: this
  }, this.options.Promise)

  this.state.activeTransition = t

  return t
}

/**
 * Create the default location.
 * This is used when no custom location is passed to
 * the listen call.
 * @return {Object} location
 *
 * @api private
 */
Cherrytree.prototype.createLocation = function (path) {
  let location = this.options.location
  if (!isString(location)) {
    return location
  }
  if (location === 'history') {
    return new HistoryLocation(pick(this.options, ['pushState', 'root']))
  } else if (location === 'memory') {
    return new MemoryLocation({path})
  } else {
    throw new Error('Location can be `history`, `memory` or a custom implementation')
  }
}

/**
 * When using pushState, it's important to setup link interception
 * because all link clicks should be handled via the router instead of
 * browser reloading the page
 */
Cherrytree.prototype.interceptLinks = function () {
  let clickHandler = typeof this.options.interceptLinks === 'function'
    ? this.options.interceptLinks
    : defaultClickHandler
  this.disposeIntercept = intercept((event, link) => clickHandler(event, link, this))

  function defaultClickHandler (event, link, router) {
    event.preventDefault()
    router.transitionTo(router.location.removeRoot(link.getAttribute('href')))
  }
}

export default function cherrytree (options) {
  return new Cherrytree(options)
}
<|endoftext|>


<commit_before>var subscriptions = new SubsManager();

Router.configure({
	loadingTemplate: 'loading',
	notFoundTemplate: 'notFound'
});

Router.route('/', {
	layoutTemplate: 'layout',
	name: 'home',
	waitOn() {
		return subscriptions.subscribe('allVolunteers');
	},
	fastRender: true
});

Router.route('/myProfile', {
	layoutTemplate: 'layout',
	name: 'myProfile',
	waitOn() {
		return subscriptions.subscribe('oneQuestionAtATime', Meteor.userId());
	},
	data() {
		return UserQuestions.findOne({
			userId: Meteor.userId(),
			answered: false,
			deprecated: false
		}, {
			sort: {
				level: 1,
				version: 1
			}
		});
	},
	fastRender: false
});

Router.route('/myDay', {
	layoutTemplate: 'layout',
	name: 'myDay',
	fastRender: false
});

Router.route('/meeting', {
	layoutTemplate: 'layout',
	name: 'meeting',
	fastRender: false
});

Router.route('/admin', {
	layoutTemplate: 'adminLayout',
	name: 'admin',
	waitOn() {
		return [
			subscriptions.subscribe('allUniverses'),
			subscriptions.subscribe('allWorkshops'),
			subscriptions.subscribe('allQuestionsGroups'),
			subscriptions.subscribe('allEkloreQuestions')
		];
	},
	fastRender: true
});

Router.route('/admin/universes/new', {
	layoutTemplate: 'adminLayout',
	name: 'newUniverse',
	fastRender: false
});

Router.route('/admin/universes/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editUniverse',
	waitOn() {
		return [subscriptions.subscribe('anUniverse', this.params._id), subscriptions.subscribe('allWorkshops')];
	},
	data() {
		return Universes.findOne(this.params._id);
	},
	fastRender: true
});

Router.route('/admin/workshops/new', {
	layoutTemplate: 'adminLayout',
	name: 'newWorkshop',
	fastRender: false
});

Router.route('/admin/workshops/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editWorkshop',
	waitOn() {
		return [subscriptions.subscribe('aWorkshop', this.params._id), subscriptions.subscribe('allUniverses')];
	},
	data() {
		return Workshops.findOne(this.params._id);
	},
	fastRender: true
});

Router.route('/admin/questionsGroups/new', {
	layoutTemplate: 'adminLayout',
	name: 'newQuestionsGroup',
	fastRender: false
});

Router.route('/admin/questionsGroups/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editQuestionsGroup',
	waitOn() {
		return [subscriptions.subscribe('aQuestionsGroup', this.params._id), subscriptions.subscribe('allEkloreQuestions')];
	},
	data() {
		return QuestionsGroups.findOne(this.params._id);
	},
	fastRender: true
});

Router.route('/admin/ekloreQuestions/new', {
	layoutTemplate: 'adminLayout',
	name: 'newEkloreQuestion',
	waitOn() {
		return [
			subscriptions.subscribe('allUniverses'),
			subscriptions.subscribe('allWorkshops')
		];
	},
	fastRender: false
});

Router.route('/admin/ekloreQuestions/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editEkloreQuestion',
	waitOn() {
		return [subscriptions.subscribe('aQuestionsGroup', this.params._id), subscriptions.subscribe('allEkloreQuestions')];
	},
	data() {
		return QuestionsGroups.findOne(this.params._id);
	},
	fastRender: true
});
<commit_msg>Update editEkloreQuestion route data and subscriptions<commit_after>var subscriptions = new SubsManager();

Router.configure({
	loadingTemplate: 'loading',
	notFoundTemplate: 'notFound'
});

Router.route('/', {
	layoutTemplate: 'layout',
	name: 'home',
	waitOn() {
		return subscriptions.subscribe('allVolunteers');
	},
	fastRender: true
});

Router.route('/myProfile', {
	layoutTemplate: 'layout',
	name: 'myProfile',
	waitOn() {
		return subscriptions.subscribe('oneQuestionAtATime', Meteor.userId());
	},
	data() {
		return UserQuestions.findOne({
			userId: Meteor.userId(),
			answered: false,
			deprecated: false
		}, {
			sort: {
				level: 1,
				version: 1
			}
		});
	},
	fastRender: false
});

Router.route('/myDay', {
	layoutTemplate: 'layout',
	name: 'myDay',
	fastRender: false
});

Router.route('/meeting', {
	layoutTemplate: 'layout',
	name: 'meeting',
	fastRender: false
});

Router.route('/admin', {
	layoutTemplate: 'adminLayout',
	name: 'admin',
	waitOn() {
		return [
			subscriptions.subscribe('allUniverses'),
			subscriptions.subscribe('allWorkshops'),
			subscriptions.subscribe('allQuestionsGroups'),
			subscriptions.subscribe('allEkloreQuestions')
		];
	},
	fastRender: true
});

Router.route('/admin/universes/new', {
	layoutTemplate: 'adminLayout',
	name: 'newUniverse',
	fastRender: false
});

Router.route('/admin/universes/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editUniverse',
	waitOn() {
		return [subscriptions.subscribe('anUniverse', this.params._id), subscriptions.subscribe('allWorkshops')];
	},
	data() {
		return Universes.findOne(this.params._id);
	},
	fastRender: true
});

Router.route('/admin/workshops/new', {
	layoutTemplate: 'adminLayout',
	name: 'newWorkshop',
	fastRender: false
});

Router.route('/admin/workshops/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editWorkshop',
	waitOn() {
		return [subscriptions.subscribe('aWorkshop', this.params._id), subscriptions.subscribe('allUniverses')];
	},
	data() {
		return Workshops.findOne(this.params._id);
	},
	fastRender: true
});

Router.route('/admin/questionsGroups/new', {
	layoutTemplate: 'adminLayout',
	name: 'newQuestionsGroup',
	fastRender: false
});

Router.route('/admin/questionsGroups/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editQuestionsGroup',
	waitOn() {
		return [subscriptions.subscribe('aQuestionsGroup', this.params._id), subscriptions.subscribe('allEkloreQuestions')];
	},
	data() {
		return QuestionsGroups.findOne(this.params._id);
	},
	fastRender: true
});

Router.route('/admin/ekloreQuestions/new', {
	layoutTemplate: 'adminLayout',
	name: 'newEkloreQuestion',
	waitOn() {
		return [
			subscriptions.subscribe('allUniverses'),
			subscriptions.subscribe('allWorkshops')
		];
	},
	fastRender: false
});

Router.route('/admin/ekloreQuestions/:_id/edit', {
	layoutTemplate: 'adminLayout',
	name: 'editEkloreQuestion',
	waitOn() {
		return [
			subscriptions.subscribe('anEkloreQuestion', this.params._id),
			subscriptions.subscribe('aQuestionsGroupForAnEkloreQuestion', this.params._id),
			subscriptions.subscribe('allQuestionsGroups')
		];
	},
	data() {
		return EkloreQuestions.findOne(this.params._id);
	},
	fastRender: true
});
<|endoftext|>


<commit_before>function assert (condition, msg) {
  if (!condition)
    throw new Error(msg);
}

IronRouter = Class.extends({
  initialize: function (options) {
    this.configure(options);
    this.routes = [];
    this._current = null;
    this._deps = new Deps.Dependency;
  },

  configure: function (options) {
    this.options = this.options || {};
    _.extend(this.options, options);
  },

  map: function (cb) {
    assert(_.isFunction(cb),
           'map requires a function as the first parameter');
    cb.call(this);
  },

  route: function (name, options, handler) {
    var route;

    assert(_.isString(name), 'name is a required parameter');

    if (options instanceof Route)
      route = options;
    else
      route = new Route(this, name, options, handler);

    this.routes[name] = route;
    this.routes.push(route);
    return route;
  },

  path: function (routeName, params) {
    assert(this.routes[routeName], 'No route found named ' + routeName);
    return this.routes[routeName].path(params);
  },

  url: function (routeName, params) {
    assert(this.routes[routeName], 'No route found named ' + routeName);
    return this.routes[routeName].url(params);
  },

  dispatch: function (path, options, cb, onUnhandled) {
    var self = this
      , routes = self.routes
      , route
      , where = Meteor.isClient ? 'client' : 'server'
      , i = 0;

    function next () {
      route = routes[i++];
      onUnhandled = onUnhandled || self.onUnhandled;

      if (!route) {
        return self.onRouteNotFound(path, options);
      }

      if (route.test(path)) {
        if (route.where !== where)
          return onUnhandled(path, options);
        self.run(path, route, options, cb, onUnhandled);
      } else next();
    }

    next();
  },

  run: function (path, route, options, cb, onUnhandled) {
    var self = this
      , context
      , where = Meteor.isClient ? 'client' : 'server';

    assert(path, 'You must run with a path');
    assert(route, 'You must provide a route to the run method');

    // one last check to see if we should handle the route here
    onUnhandled = onUnhandled || self.onUnhandled;
    if (route.where != where)
      onUnhandled && onUnhandled(path, options);

    context = new RouteContext(path, this, route, options);

    this._current = context;
    this.onRun(context, _.extend({}, self.options, route.options));

    if (context == this._current) {
      cb && cb(context);
      this._deps.changed();
    }
  },

  current: function () {
    this._deps.depend();
    return this._current;
  },

  onRun: function (context, options) {
    throw new Error('onRun not implemented');
  },

  onUnhandled: function (path, options) {
    throw new Error('onUnhandled not implemented');
  },

  onRouteNotFound: function (path, options) {
    throw new Error('No route found for path: ' + path);
  }
});
<commit_msg>Better error messages for Route.path and Route.url.<commit_after>function assert (condition, msg) {
  if (!condition)
    throw new Error(msg);
}

IronRouter = Class.extends({
  initialize: function (options) {
    this.configure(options);
    this.routes = [];
    this._current = null;
    this._deps = new Deps.Dependency;
  },

  configure: function (options) {
    this.options = this.options || {};
    _.extend(this.options, options);
  },

  map: function (cb) {
    assert(_.isFunction(cb),
           'map requires a function as the first parameter');
    cb.call(this);
  },

  route: function (name, options, handler) {
    var route;

    assert(_.isString(name), 'name is a required parameter');

    if (options instanceof Route)
      route = options;
    else
      route = new Route(this, name, options, handler);

    this.routes[name] = route;
    this.routes.push(route);
    return route;
  },

  path: function (routeName, params) {
    assert(this.routes[routeName], 'path: No route found named ' + routeName);
    return this.routes[routeName].path(params);
  },

  url: function (routeName, params) {
    assert(this.routes[routeName], 'url: No route found named ' + routeName);
    return this.routes[routeName].url(params);
  },

  dispatch: function (path, options, cb, onUnhandled) {
    var self = this
      , routes = self.routes
      , route
      , where = Meteor.isClient ? 'client' : 'server'
      , i = 0;

    function next () {
      route = routes[i++];
      onUnhandled = onUnhandled || self.onUnhandled;

      if (!route) {
        return self.onRouteNotFound(path, options);
      }

      if (route.test(path)) {
        if (route.where !== where)
          return onUnhandled(path, options);
        self.run(path, route, options, cb, onUnhandled);
      } else next();
    }

    next();
  },

  run: function (path, route, options, cb, onUnhandled) {
    var self = this
      , context
      , where = Meteor.isClient ? 'client' : 'server';

    assert(path, 'You must run with a path');
    assert(route, 'You must provide a route to the run method');

    // one last check to see if we should handle the route here
    onUnhandled = onUnhandled || self.onUnhandled;
    if (route.where != where)
      onUnhandled && onUnhandled(path, options);

    context = new RouteContext(path, this, route, options);

    this._current = context;
    this.onRun(context, _.extend({}, self.options, route.options));

    if (context == this._current) {
      cb && cb(context);
      this._deps.changed();
    }
  },

  current: function () {
    this._deps.depend();
    return this._current;
  },

  onRun: function (context, options) {
    throw new Error('onRun not implemented');
  },

  onUnhandled: function (path, options) {
    throw new Error('onUnhandled not implemented');
  },

  onRouteNotFound: function (path, options) {
    throw new Error('No route found for path: ' + path);
  }
});
<|endoftext|>


<commit_before>Router.configure({
    layoutTemplate: 'appBody',
    // notFoundTemplate: 'appNotFound',
    // loadingTemplate: 'appLoading',
});

Router.map(function(){
    this.route('/', {
        name: 'home',
    });
    this.route('events', {
        name: 'events',
        waitOn: function () {
            return [
                Meteor.subscribe('parseEvents')
            ];
        }
    });
});
<commit_msg>only display events to logged users<commit_after>Router.configure({
    layoutTemplate: 'appBody',
    // notFoundTemplate: 'appNotFound',
    // loadingTemplate: 'appLoading',
});

Router.onBeforeAction(function () {
    if (! Meteor.userId()) {
        Router.go('home');
    } else {
        this.next();
    }
}, {only: ['events']});

Router.map(function(){
    this.route('/', {
        name: 'home',
    });
    this.route('events', {
        name: 'events',
        waitOn: function () {
            return [
                Meteor.subscribe('parseEvents')
            ];
        }
    });
});
<|endoftext|>


<commit_before>'use strict';

var api = require('./modules/api');

module.exports = function (app) {

    /* Users
=================================================================== */
    app.use('/api/users', require('./modules/user').router);

    /* Session
=================================================================== */
    app.use('/api/session', require('./modules/session').router);

    /* App API
=================================================================== */
    app.use('/api/files', require('./modules/file').router);
    app.use('/api/broker', require('./modules/settings/broker').router);
    app.use('/api/supplier', require('./modules/settings/supplier').router);
    app.use('/api/forwarder', require('./modules/settings/forwarder').router);
    app.use('/api/material', require('./modules/settings/material').router);
    app.use('/api/shippinglines', require('./modules/settings/shippinglines').router);
    app.use('/api/planner', require('./modules/initiateimport/planner').router);

    /* Partials
=================================================================== */
    app.use('/', require('./modules/index').router);
};<commit_msg>added routes for regulatorydocuments<commit_after>'use strict';

var api = require('./modules/api');

module.exports = function (app) {

    /* Users
=================================================================== */
    app.use('/api/users', require('./modules/user').router);

    /* Session
=================================================================== */
    app.use('/api/session', require('./modules/session').router);

    /* App API
=================================================================== */
    app.use('/api/broker', require('./modules/settings/broker').router);
    app.use('/api/supplier', require('./modules/settings/supplier').router);
    app.use('/api/forwarder', require('./modules/settings/forwarder').router);
    app.use('/api/material', require('./modules/settings/material').router);
    app.use('/api/shippinglines', require('./modules/settings/shippinglines').router);
    app.use('/api/regulatorydocuments', require('./modules/settings/regulatorydocuments').router);

    app.use('/api/planner', require('./modules/initiateimport/planner').router);

    /* Partials
=================================================================== */
    app.use('/', require('./modules/index').router);
};<|endoftext|>


<commit_before>var db = require('mongoose');
var Log = require('log'), log = new Log('info');

var log = new Log('info');

var models = null;
exports.setModels = function(models_) {
  models = models_;
}
/** DB API generic */
exports.genericDBAPI = function(req, res) {
  try {
    var query = req.query;
    var opts = {};
    var limit = 5000;
    var sort = {};
    var fields = '';
    for (q in query) {
      try {
        if (q === 'limit') limit = parseInt(query[q]);
        else if (q === 'sort') sort = query[q];
        else if (q === 'fields') fields = query[q];
        else if (q === '_') continue; // jquery ajax cache param
        else {
          opts[q] = JSON.parse(query[q]);
        }
      } catch (ex) {
        opts[q] = query[q];
      }
    }
    var model = getModelForName(req.params.collection);
    if (model === null) {
      res.send(404, req.params.collection+ ' is unknown');
    } else {
      var errorDetected = false;
      var qry = model.find(opts, fields).limit(limit).sort(sort).lean(true);
      var qrystream = qry.stream();
      data = [];
      qrystream.on('data', function(doc) {
        data.push(doc);
      });
      qrystream.on('error', function(err) {
        errorDetected = true;
        //log.error('mongodbview - stream on /api/db/ %s', err);
        res.send(500, err.message);
      });
      qrystream.on('close', function () {
        if (!errorDetected) {
          res.set({'Content-Type': 'application/json', 'Cache-Control' : 'no-cache,no-store,must-revalidate'});
          res.send(200, JSON.stringify(data));
        }
      });
    }
  } catch (ex) {
    if (req.params && req.params.collection) log.error('mongodbview - /api/db/%s Error: %s', req.params.collection, ex);
    else log.error('mongodbview - /api/db (req.params.collection unknown) Error: %s ', ex);
    res.send(500, ex.toString());
  }
}

exports.count = function(req, res) {
  try {
    var model = getModelForName(req.params.collection);
    if (model === null) {
      res.send(404, req.params.collection+ ' is unknown');
    } else {
      var qry = model.count();
      qry.exec(function(err, doc) {
        if (err !== null) res.send(500, err);
        else {
          res.set({'Content-Type': 'text/plain', 'Cache-Control' : 'no-cache,no-store,must-revalidate'});
          res.send(200, JSON.stringify(doc));
        }
      });
    }
  } catch (ex) {
    if (req.params && req.params.collection) log.error('mongodbview - /api/db/count/%s Error: %s', req.params.collection, ex);
    else log.error('mongodbview - /api/db/count (req.params.collection unknown) Error: %s ', ex);
    res.send(500, ex.toString());
  }
}

var getModelForName = function(modelName) {
  for (var m = 0, mx = models.length; m < mx; ++m) {
    if (models[m].modelName === modelName) return models[m];
  }
  return null;
}<commit_msg>reducing limit to 1000, added jqgrid request params<commit_after>var db = require('mongoose');
var Log = require('log'), log = new Log('info');

var log = new Log('info');

var models = null;
exports.setModels = function(models_) {
  models = models_;
}
/** DB API generic */
exports.genericDBAPI = function(req, res) {
  try {
    var query = req.query;
    var opts = {};
    var limit = 1000;
    var sort = {};
    var fields = '';
    for (q in query) {
      try {
        if (q === 'limit') limit = parseInt(query[q], 10);
        else if (q === 'sort') sort = query[q];
        else if (q === 'fields') fields = query[q];
        else if (q === '_') continue; // jquery ajax cache param
        else if (q === 'nd') continue; // jquery ajax cache param
        else if (q === 'rows') limit = parseInt(query[q], 10); // jqgrid
        else if (q === '_search') continue; // jqgrid
        else if (q === 'page') continue; // jqgrid
        else if (q === 'sidx') sort = query[q]; // jqgrid
        else if (q === 'sord') continue; // jqgrid
        else {
          opts[q] = JSON.parse(query[q]);
        }
      } catch (ex) {
        opts[q] = query[q];
      }
    }
    var model = getModelForName(req.params.collection);
    if (model === null) {
      res.send(404, req.params.collection+ ' is unknown');
    } else {
      var errorDetected = false;
      var qry = model.find(opts, fields).limit(limit).sort(sort).lean(true);
      var qrystream = qry.stream();
      data = [];
      qrystream.on('data', function(doc) {
        data.push(doc);
      });
      qrystream.on('error', function(err) {
        errorDetected = true;
        //log.error('mongodbview - stream on /api/db/ %s', err);
        res.send(500, err.message);
      });
      qrystream.on('close', function () {
        if (!errorDetected) {
          res.set({'Content-Type': 'application/json', 'Cache-Control' : 'no-cache,no-store,must-revalidate'});
          res.send(200, JSON.stringify(data));
        }
      });
    }
  } catch (ex) {
    if (req.params && req.params.collection) log.error('mongodbview - /api/db/%s Error: %s', req.params.collection, ex);
    else log.error('mongodbview - /api/db (req.params.collection unknown) Error: %s ', ex);
    res.send(500, ex.toString());
  }
}

exports.count = function(req, res) {
  try {
    var model = getModelForName(req.params.collection);
    if (model === null) {
      res.send(404, req.params.collection+ ' is unknown');
    } else {
      var qry = model.count();
      qry.exec(function(err, doc) {
        if (err !== null) res.send(500, err);
        else {
          res.set({'Content-Type': 'text/plain', 'Cache-Control' : 'no-cache,no-store,must-revalidate'});
          res.send(200, JSON.stringify(doc));
        }
      });
    }
  } catch (ex) {
    if (req.params && req.params.collection) log.error('mongodbview - /api/db/count/%s Error: %s', req.params.collection, ex);
    else log.error('mongodbview - /api/db/count (req.params.collection unknown) Error: %s ', ex);
    res.send(500, ex.toString());
  }
}

var getModelForName = function(modelName) {
  for (var m = 0, mx = models.length; m < mx; ++m) {
    if (models[m].modelName === modelName) return models[m];
  }
  return null;
}<|endoftext|>


<commit_before>Router.configure({
  layoutTemplate: '_layout'
});

//From what I can tell this has been depreciated
//https://github.com/iron-meteor/iron-router/blob/739bcc1445db3ad6bf90bda4e0cab3203a0ae526/lib/router.js#L88
Router.map(function() {
  // initiative routes
  this.route('initiatives', {
    path: '/',
    template: 'initiatives',
    data: function() {
        return {
          userData: Meteor.subscribe("userData"),
          initiatives: Initiatives.find({}, {sort: {votes: -1}})
      }
    },
    onAfterAction: function() {
      if(Session.equals('accountCreated', true)) {
        sAlert.success('Account created. Welcome to Cherish!');
        delete Session.keys['accountCreated'];
      }
    }
  });

  this.route('category', {
    path: '/category/:category',
    template: 'initiatives',
    data: function() {
        return {
          userData: Meteor.subscribe("userData"),
          initiatives: Initiatives.find({categorySlug: this.params.category}, {sort: {votes: -1}})
      }
    }
  });

  this.route('initiative', {
    path: '/initiative/:slug',
    template: 'initiativeShow',
    data: function () {
      return {
        userData: Meteor.subscribe("userData"),
        initiative: Initiatives.findOne({slug: this.params.slug})
      }
    }
  });

  this.route('profile', {
    path: '/profile',
    template: 'profileShow',
    data: function() {
      return {
        profile: Meteor.user()
      }
    },
    action: function(){
      if(!Meteor.userId()){
        Router.go('initiatives');
      }
    }
  });

  // login routes
  this.route('login', {
    path: '/login',
    template: 'publicLogin'
  });

  this.route('signup', {
    path: '/signup',
    template: 'publicSignup'
  });

  this.route('about');
});<commit_msg>Fix router, that i broke in profile fix<commit_after>Router.configure({
  layoutTemplate: '_layout'
});

//From what I can tell this has been depreciated
//https://github.com/iron-meteor/iron-router/blob/739bcc1445db3ad6bf90bda4e0cab3203a0ae526/lib/router.js#L88
Router.map(function() {
  // initiative routes
  this.route('initiatives', {
    path: '/',
    template: 'initiatives',
    data: function() {
        return {
          userData: Meteor.subscribe("userData"),
          initiatives: Initiatives.find({}, {sort: {votes: -1}})
      }
    },
    onAfterAction: function() {
      if(Session.equals('accountCreated', true)) {
        sAlert.success('Account created. Welcome to Cherish!');
        delete Session.keys['accountCreated'];
      }
    }
  });

  this.route('category', {
    path: '/category/:category',
    template: 'initiatives',
    data: function() {
        return {
          userData: Meteor.subscribe("userData"),
          initiatives: Initiatives.find({categorySlug: this.params.category}, {sort: {votes: -1}})
      }
    }
  });

  this.route('initiative', {
    path: '/initiative/:slug',
    template: 'initiativeShow',
    data: function () {
      return {
        userData: Meteor.subscribe("userData"),
        initiative: Initiatives.findOne({slug: this.params.slug})
      }
    }
  });

  this.route('profile', {
    path: '/profile',
    template: 'profileShow',
    data: function() {
      return {
        profile: Meteor.user()
      }
    },
    action: function(){
      if(!Meteor.userId()){
        Router.go('initiatives');
      } else {
        this.render();
      }
    }
  });

  // login routes
  this.route('login', {
    path: '/login',
    template: 'publicLogin'
  });

  this.route('signup', {
    path: '/signup',
    template: 'publicSignup'
  });

  this.route('about');
});<|endoftext|>


<commit_before>'use strict';

var Controllers = require('./controllers')();

/**
* Routing definitions.
* @namespace routes
*/

/**
* Registers all API routes available
* @param {express} app - Application to register API routes with.
* @function routes.route
*/
module.exports.route = function (app) {

  // ================================
  // Login Routes
  // ================================

  /**
  * @apiDefine auth Authentication
  * @apiParam (GET) {string} [token] Token from the current session. Not needed when the openjub_session cookie is available.
  * @apiParam (COOKIE) {string} [openjub_session] Session cookie containing a logged in session. If not given, the GET parameter token is mandatory.
  */

  /**
   * @api {get} /login/isoncampus On Campus location
   * @apiDescription Check it the request in On or Off Campus.
   * @apiGroup Login
   *
   * @apiVersion 0.1.0
   * @apiSuccess {String} on_campus Is the user on or off campus?
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "on_campus": true
   *    }
   */
  app.get('/login/isoncampus', Controllers.Login.checkCampus);

  /**
   * @api {post} /login/signin CampusNet Authentication
   * @apiDescription Login with CampusNet details.
   * @apiGroup Login
   *
   * @apiParam {String} username CampusNet/LDAP username
   * @apiParam {String} password CampusNet/LDAP password
   *
   * @apiSuccess {String} token Login Token
   * @apiSuccess {String} user Username
   *
   * @apiVersion 0.1.0
   * @apiUse InvalidRequest
   * @apiUse InvalidAuthentication
   * @apiUse AlreadyAuthenticated
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "token": "<token>",
   *      "user": "ex.ample"
   *    }
   */
  app.post('/login/signin', Controllers.Login.signin);

  /**
   * @api {get} /login/signout Signout
   * @apiDescription Logout of a session.
   * @apiGroup Login
   *
   * @apiSuccess {Boolean} success indicating if the logout was successfull.
   *
   * @apiVersion 0.1.0
   * @apiUse auth
   * @apiUse TokenNotFound
   * @apiUse UnknownError
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "success": true
   *    }
   */
  app.get('/login/signout', Controllers.Login.need, Controllers.Login.signout);

  /**
   * @api {post} /login/status Login Status
   * @apiDescription If logged in, check the login status.
   * @apiGroup Login
   *
   * @apiSuccess {String} token Login Token
   * @apiSuccess {String} user Username or False when using on-Campus authentication.
   *
   * @apiVersion 0.1.0
   * @apiUse auth
   * @apiUse TokenNotFound
   * @apiUse InvalidRequest
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "token": "<token>",
   *      "user": "ex.ample"
   *    }
   */
  app.get('/login/status', Controllers.Login.need, Controllers.Login.status);

  // ================================
  // Everything else
  // ================================

  app.get('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
  app.post('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
  app.put('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
  app.delete('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
};
<commit_msg>F*** it, users are not goats<commit_after>'use strict';

var Controllers = require('./controllers')();

/**
* Routing definitions.
* @namespace routes
*/

/**
* Registers all API routes available
* @param {express} app - Application to register API routes with.
* @function routes.route
*/
module.exports.route = function (app) {

  // ================================
  // Login Routes
  // ================================

  /**
  * @apiDefine auth Authentication
  * @apiParam (GET) {string} [token] Token from the current session. Not needed when the openjub_session cookie is available.
  * @apiParam (COOKIE) {string} [openjub_session] Session cookie containing a logged in session. If not given, the GET parameter token is mandatory.
  */

  /**
   * @api {get} /login/isoncampus On Campus location
   * @apiDescription Check it the request in On or Off Campus.
   * @apiGroup Login
   *
   * @apiVersion 0.1.0
   * @apiSuccess {String} on_campus Is the user on or off campus?
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "on_campus": true
   *    }
   */
  app.get('/login/isoncampus', Controllers.Login.checkCampus);

  /**
   * @api {post} /login/signin CampusNet Authentication
   * @apiDescription Login with CampusNet details.
   * @apiGroup Login
   *
   * @apiParam {String} username CampusNet/LDAP username
   * @apiParam {String} password CampusNet/LDAP password
   *
   * @apiSuccess {String} token Login Token
   * @apiSuccess {String} user Username
   *
   * @apiVersion 0.1.0
   * @apiUse InvalidRequest
   * @apiUse InvalidAuthentication
   * @apiUse AlreadyAuthenticated
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "token": "<token>",
   *      "user": "ex.ample"
   *    }
   */
  app.post('/login/signin', Controllers.Login.signin);

  /**
   * @api {get} /login/signout Signout
   * @apiDescription Logout of a session.
   * @apiGroup Login
   *
   * @apiSuccess {Boolean} success indicating if the logout was successfull.
   *
   * @apiVersion 0.1.0
   * @apiUse auth
   * @apiUse TokenNotFound
   * @apiUse UnknownError
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "success": true
   *    }
   */
  app.get('/login/signout', Controllers.Login.need, Controllers.Login.signout);

  /**
   * @api {post} /login/status Login Status
   * @apiDescription If logged in, check the login status.
   * @apiGroup Login
   *
   * @apiSuccess {String} token Login Token
   * @apiSuccess {String} user Username or False when using on-Campus authentication.
   *
   * @apiVersion 0.1.0
   * @apiUse auth
   * @apiUse TokenNotFound
   * @apiUse InvalidRequest
   *
   * @apiSuccessExample Success-Response
   *    HTTP/1.1 200 OK
   *    {
   *      "token": "<token>",
   *      "user": "ex.ample"
   *    }
   */
  app.get('/login/status', Controllers.Login.need, Controllers.Login.status);

  // ================================
  // /user/me
  // ================================

  //we're not a goat
  app.get('/user/me/isagoat', function(req, res){
    res.jsonp({
      "isAGoat": false
    });
  })

  // ================================
  // Everything else
  // ================================

  app.get('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
  app.post('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
  app.put('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
  app.delete('/*', function (req, res) {
    res.errorJson('RequestNotFound');
  });
};
<|endoftext|>