<commit_before>Reports = new Mongo.Collection('reports');
Tags = new Mongo.Collection('tags');

function getSubmitterId(reportId) {
  return Reports.findOne(reportId).createdBy;
}

Meteor.methods({
  createReport: function (text, tags = []) {
    const user = Meteor.users.findOne(this.userId);
    const report = Reports.insert({
      source: 'user',
      text: text,
      tags: tags,
      thanks: [],
      allthanks: [],
      upvotes: [],
      downvotes: [],
      createdAt: new Date(),
      createdBy: this.userId,
      sourceName: user.profile.nickname,
      expired: false,
      removed: false,
      token: Random.id(),
      weight: CONFIG.initialWeight
    });

    if (Meteor.isServer) {
      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-created': report}
      });
    }

    return report;

  },

  updateReport: function(reportId, token, fields) {
    if (Meteor.isServer) {
      var updated = Reports.update({
        _id: reportId,
        token: token
      }, {
        $set: fields
      });

      if (updated === 0) {
        throw new Meteor.Error('bad-token', 'Zły żeton.');
      }

      var report = Reports.findOne(reportId);

      if (!report.pushed) {
        pushReport.call(this, report);
        Reports.update(reportId, {
          $set: { pushed: true }
        });
      }
    }
  },

  thankReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      thanks: { $ne: this.userId }
    }, {
      $addToSet: {
        thanks: this.userId,
      }
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'thanks-not-allowed', 'Nie można wysłać podziękowań.');
    }

    if (Meteor.isServer) {
      var submitterId = getSubmitterId(reportId);

      Meteor.users.update(submitterId, {
        $addToSet: {'incoming.reports-thanked': reportId}
      });

      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-thanked': reportId}
      });

      const everThanked = Reports.find({
        _id: reportId,
        allthanks: this.userId
      }).count();

      if (!everThanked) {
        pushThanks.call(this, reportId, submitterId, this.userId);
      }
    }
  },

  cancelThanks: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      thanks: this.userId
    }, {
      $pull: {thanks: this.userId}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'thanks-not-allowed', 'Nie można wysłać podziękowań.');
    }

    if (Meteor.isServer) {
      var submitterId = getSubmitterId(reportId);

      Meteor.users.update(submitterId, {
        $pull: {'incoming.reports-thanked': reportId}
      });

      Meteor.users.update(this.userId, {
        $pull: {'outgoing.reports-thanked': reportId}
      });
    }
  },

  upvoteReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      upvotes: { $ne: this.userId }
    }, {
      $addToSet: {upvotes: this.userId},
      $inc: {weight: CONFIG.upvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'upvote-not-allowed', 'Nie można potwierdzić raportu.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $addToSet: {'incoming.reports-upvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-upvoted': reportId}
      });
    }
  },

  cancelUpvote: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      upvotes: this.userId
    }, {
      $pull: {upvotes: this.userId},
      $inc: {weight: -CONFIG.upvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'cancel-upvote-not-allowed', 'Nie można anulować potwierdzenia.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $pull: {'incoming.reports-upvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $pull: {'outgoing.reports-upvoted': reportId}
      });
    }
  },

  downvoteReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      downvotes: { $ne: this.userId }
    }, {
      $addToSet: {downvotes: this.userId},
      $inc: {weight: CONFIG.downvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'downvote-not-allowed', 'Nie można odwołać raportu.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $addToSet: {'incoming.reports-downvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-downvoted': reportId}
      });
    }
  },

  cancelDownvote: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      downvotes: this.userId
    }, {
      $pull: {downvotes: this.userId},
      $inc: {weight: -CONFIG.downvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'cancel-downvote-not-allowed', 'Nie można anulować odwołania.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $pull: {'incoming.reports-downvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $pull: {'outgoing.reports-downvoted': reportId}
      });
    }
  },

  removeReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: this.userId,
    }, {
      $set: {removed: true}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'remove-not-allowed', 'Nie można usunąć zgłoszenia.');
    }
  },

  cancelRemove: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: this.userId,
      removed: true,
    }, {
      $set: {removed: false}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'remove-not-allowed', 'Nie można przywrócić zgłoszenia.');
    }
  },

  dismissReport: function(reportId) {
    Reports.update(reportId, {
      $addToSet: {
        dismissedBy: this.userId
      }
    });
  },

  cancelDismiss: function(reportId) {
    Reports.update(reportId, {
      $pull: {
        dismissedBy: this.userId
      }
    });
  },

  commentReport: function(reportId, text) {
    const user = Meteor.users.findOne(this.userId);
    const comment = {
      text: text,
      createdAt: new Date(),
      createdBy: this.userId,
      sourceName: user.profile.nickname,
    };
    const updated = Reports.update({
      _id: reportId,
    }, {
      $addToSet: {comments: comment},
      $set: {lastComment: comment},
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'comment-unknown-error', 'Nie można skomentować raportu.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $push: {'incoming.reports-commented': reportId}
      });

      Meteor.users.update(this.userId, {
        $push: {'outgoing.reports-commented': reportId}
      });
    }
  },

});
<commit_msg>push right away<commit_after>Reports = new Mongo.Collection('reports');
Tags = new Mongo.Collection('tags');

function getSubmitterId(reportId) {
  return Reports.findOne(reportId).createdBy;
}

Meteor.methods({
  createReport: function (text, tags = []) {
    const user = Meteor.users.findOne(this.userId);
    const reportId = Reports.insert({
      source: 'user',
      text: text,
      tags: tags,
      thanks: [],
      allthanks: [],
      upvotes: [],
      downvotes: [],
      createdAt: new Date(),
      createdBy: this.userId,
      sourceName: user.profile.nickname,
      expired: false,
      removed: false,
      token: Random.id(),
      weight: CONFIG.initialWeight
    });

    if (Meteor.isServer) {
      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-created': reportId}
      });

      var report = Reports.findOne(reportId);
      pushReport.call(this, report);
      Reports.update(reportId, {
        $set: { pushed: true }
      });
    }

    return reportId;

  },

  updateReport: function(reportId, token, fields) {
    if (Meteor.isServer) {
      var updated = Reports.update({
        _id: reportId,
        token: token
      }, {
        $set: fields
      });

      if (updated === 0) {
        throw new Meteor.Error('bad-token', 'Zły żeton.');
      }

      var report = Reports.findOne(reportId);

      if (!report.pushed) {
        pushReport.call(this, report);
        Reports.update(reportId, {
          $set: { pushed: true }
        });
      }
    }
  },

  thankReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      thanks: { $ne: this.userId }
    }, {
      $addToSet: {
        thanks: this.userId,
      }
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'thanks-not-allowed', 'Nie można wysłać podziękowań.');
    }

    if (Meteor.isServer) {
      var submitterId = getSubmitterId(reportId);

      Meteor.users.update(submitterId, {
        $addToSet: {'incoming.reports-thanked': reportId}
      });

      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-thanked': reportId}
      });

      const everThanked = Reports.find({
        _id: reportId,
        allthanks: this.userId
      }).count();

      if (!everThanked) {
        pushThanks.call(this, reportId, submitterId, this.userId);
      }
    }
  },

  cancelThanks: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      thanks: this.userId
    }, {
      $pull: {thanks: this.userId}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'thanks-not-allowed', 'Nie można wysłać podziękowań.');
    }

    if (Meteor.isServer) {
      var submitterId = getSubmitterId(reportId);

      Meteor.users.update(submitterId, {
        $pull: {'incoming.reports-thanked': reportId}
      });

      Meteor.users.update(this.userId, {
        $pull: {'outgoing.reports-thanked': reportId}
      });
    }
  },

  upvoteReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      upvotes: { $ne: this.userId }
    }, {
      $addToSet: {upvotes: this.userId},
      $inc: {weight: CONFIG.upvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'upvote-not-allowed', 'Nie można potwierdzić raportu.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $addToSet: {'incoming.reports-upvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-upvoted': reportId}
      });
    }
  },

  cancelUpvote: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      upvotes: this.userId
    }, {
      $pull: {upvotes: this.userId},
      $inc: {weight: -CONFIG.upvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'cancel-upvote-not-allowed', 'Nie można anulować potwierdzenia.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $pull: {'incoming.reports-upvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $pull: {'outgoing.reports-upvoted': reportId}
      });
    }
  },

  downvoteReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      downvotes: { $ne: this.userId }
    }, {
      $addToSet: {downvotes: this.userId},
      $inc: {weight: CONFIG.downvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'downvote-not-allowed', 'Nie można odwołać raportu.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $addToSet: {'incoming.reports-downvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $addToSet: {'outgoing.reports-downvoted': reportId}
      });
    }
  },

  cancelDownvote: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: { $ne: this.userId },
      downvotes: this.userId
    }, {
      $pull: {downvotes: this.userId},
      $inc: {weight: -CONFIG.downvoteWeight}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'cancel-downvote-not-allowed', 'Nie można anulować odwołania.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $pull: {'incoming.reports-downvoted': reportId}
      });

      Meteor.users.update(this.userId, {
        $pull: {'outgoing.reports-downvoted': reportId}
      });
    }
  },

  removeReport: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: this.userId,
    }, {
      $set: {removed: true}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'remove-not-allowed', 'Nie można usunąć zgłoszenia.');
    }
  },

  cancelRemove: function(reportId) {
    var updated = Reports.update({
      _id: reportId,
      createdBy: this.userId,
      removed: true,
    }, {
      $set: {removed: false}
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'remove-not-allowed', 'Nie można przywrócić zgłoszenia.');
    }
  },

  dismissReport: function(reportId) {
    Reports.update(reportId, {
      $addToSet: {
        dismissedBy: this.userId
      }
    });
  },

  cancelDismiss: function(reportId) {
    Reports.update(reportId, {
      $pull: {
        dismissedBy: this.userId
      }
    });
  },

  commentReport: function(reportId, text) {
    const user = Meteor.users.findOne(this.userId);
    const comment = {
      text: text,
      createdAt: new Date(),
      createdBy: this.userId,
      sourceName: user.profile.nickname,
    };
    const updated = Reports.update({
      _id: reportId,
    }, {
      $addToSet: {comments: comment},
      $set: {lastComment: comment},
    });

    if (updated === 0) {
      throw new Meteor.Error(
        'comment-unknown-error', 'Nie można skomentować raportu.');
    }

    if (Meteor.isServer) {
      Meteor.users.update(getSubmitterId(reportId), {
        $push: {'incoming.reports-commented': reportId}
      });

      Meteor.users.update(this.userId, {
        $push: {'outgoing.reports-commented': reportId}
      });
    }
  },

});
<|endoftext|>


<commit_before>'use strict';

const Emitter = require('@sellside/emitter');
const define = require('./define');
const Route = require('./route');

/**
 * Create a new `Router` with the given options.
 *
 * ```js
 * const route = new Router({ handlers: ['preWrite', 'postWrite']});
 * ```
 * @name Route
 * @extends {Class} Emitter
 * @param {object} `options`
 * @api public
 */

class Router extends Emitter {
  constructor(options = {}) {
    super();
    this.options = options;
    this.methods = new Set();
    this.routes = new Map();
    this.handlers(this.options.handlers, this.options);
  }

  /**
   * Create a middleware handler method.
   * @name .handler
   * @param {string} `method` Method name
   * @param {object} `options`
   * @return {object} Returns the instance for chaining.
   * @api public
   */

  handler(method, options) {
    if (Array.isArray(method)) return this.handlers(method, options);
    if (!this.routes.has(method)) this.routes.set(method, new Set());

    if (typeof method !== 'string') {
      throw new TypeError('expected handler method name to be a string');
    }

    const opts = Object.assign({}, this.options, options);
    const stack = this.routes.get(method);

    const handler = (pattern, ...fns) => {
      if (Array.isArray(pattern) && typeof pattern[0] !== 'function') {
        pattern.forEach(p => handler(p, ...fns));
        return this;
      }
      const route = new Route(pattern, fns, opts);
      route.on('layer', this.emit.bind(this, 'layer', method));
      route.on('handle', file => {
        this.emit('handle', method, file, route);
        this.emit(method, file, route);
      });
      stack.add(route);
      return this;
    };

    define(this, method, handler);
    this.methods.add(method);
    this.emit('handler', method, handler);
    return handler;
  }

  /**
   * Create a new router instance with all handler methods bound to the given pattern.
   *
   * ```js
   * const router = new Router({ handlers: ['before', 'after'] });
   * const file = { path: '/foo', content: '' };
   *
   * router.route('/foo')
   *   .before(function(file) {
   *     file.content += 'foo';
   *   })
   *   .after(function(file) {
   *     file.content += 'bar';
   *   });
   *
   * router.handle(file)
   *   .then(() => {
   *     assert.equal(file.content, 'foobar');
   *   });
   * ```
   * @name .route
   * @param {string} `pattern`
   * @return {object} Returns a new router instance with handler methods bound to the given pattern.
   * @api public
   */

  route(pattern, options) {
    const router = new this.constructor(options);
    for (const method of this.methods) {
      router[method] = (...fns) => router.handler(method)(pattern, ...fns);
    }
    return router;
  }

  /**
   * Add one or more middleware handler methods. Handler methods may also be
   * added by passing an array of handler names to the constructor on the
   * `handlers` option.
   *
   * ```js
   * router.handlers(['onLoad', 'preRender']);
   * ```
   * @name .handlers
   * @param {string} `methods` Method names
   * @param {object} `options`
   * @return {object} Returns the instance for chaining.
   * @api public
   */

  handlers(methods, options) {
    arrayify(methods).forEach(name => this.handler(name, options));
    return this;
  }

  /**
   * Run a middleware methods on the given `file`.
   *
   * ```js
   * // run a specific method
   * router.handle('onLoad', file)
   *   .then(file => console.log('File:', file))
   *   .catch(console.error);
   *
   * // run multiple methods
   * router.handle('onLoad', file)
   *   .then(file => router.handle('preRender', file))
   *   .catch(console.error);
   *
   * // run all methods
   * router.handle(file)
   *   .then(file => console.log('File:', file))
   *   .catch(console.error);
   * ```
   * @name .handle
   * @param {string|file} `method` The handler method to call on `file`. If the first argument is a file object, all handlers will be called on the file.
   * @param {object} `file` File object
   * @return {Promise}
   * @api public
   */

  async handle(method, file) {
    if (typeof method === 'object' && method !== null) {
      for (const name of this.methods) await this.handle(name, method);
      return method;
    }

    if (!this.routes.has(method)) {
      throw new Error(`Router handler "${method}" does not exist`);
    }

    for (const route of this.routes.get(method)) await route.handle(file);
    return file;
  }

  /**
   * Register all handler methods on the given file.
   *
   * ```js
   * router.all(file => {
   *   file.data.title = 'Home';
   * });
   * ```
   * @name .all
   * @param {object} `file` File object
   * @return {Promise}
   * @api public
   */

  async all(file, options) {
    return this.handle(file, options);
  }

  /**
   * Mix router methods onto the given object.
   *
   * ```js
   * const router = new Router();
   * const obj = {};
   * router.handlers(['before', 'after']);
   * router.mixin(obj);
   * console.log(obj.before) //=> [function]
   * ```
   * @name .mixin
   * @param {object} `target`
   * @return {undefined}
   * @api public
   */

  mixin(target) {
    define(target, 'all', this.all.bind(this));
    for (const name of this.methods) {
      define(target, name, this[name].bind(this));
    }
    return this;
  }
}

function arrayify(val) {
  return val ? Array.isArray(val) ? val : [val] : [];
}

/**
 * Expose `Router`
 */

module.exports = Router;
<commit_msg>clarify logic for `.all`<commit_after>'use strict';

const Emitter = require('@sellside/emitter');
const define = require('./define');
const Route = require('./route');

/**
 * Create a new `Router` with the given options.
 *
 * ```js
 * const route = new Router({ handlers: ['preWrite', 'postWrite']});
 * ```
 * @name Route
 * @extends {Class} Emitter
 * @param {object} `options`
 * @api public
 */

class Router extends Emitter {
  constructor(options = {}) {
    super();
    this.options = options;
    this.methods = new Set();
    this.routes = new Map();
    this.handlers(this.options.handlers, this.options);
  }

  /**
   * Create a middleware handler method.
   * @name .handler
   * @param {string} `method` Method name
   * @param {object} `options`
   * @return {object} Returns the instance for chaining.
   * @api public
   */

  handler(method, options) {
    if (Array.isArray(method)) return this.handlers(method, options);
    if (!this.routes.has(method)) this.routes.set(method, new Set());

    if (typeof method !== 'string') {
      throw new TypeError('expected handler method name to be a string');
    }

    const opts = Object.assign({}, this.options, options);
    const stack = this.routes.get(method);

    const handler = (pattern, ...fns) => {
      if (Array.isArray(pattern) && typeof pattern[0] !== 'function') {
        pattern.forEach(p => handler(p, ...fns));
        return this;
      }
      const route = new Route(pattern, fns, opts);
      route.on('layer', this.emit.bind(this, 'layer', method));
      route.on('handle', file => {
        this.emit('handle', method, file, route);
        this.emit(method, file, route);
      });
      stack.add(route);
      return this;
    };

    define(this, method, handler);
    this.methods.add(method);
    this.emit('handler', method, handler);
    return handler;
  }

  /**
   * Create a new router instance with all handler methods bound to the given pattern.
   *
   * ```js
   * const router = new Router({ handlers: ['before', 'after'] });
   * const file = { path: '/foo', content: '' };
   *
   * router.route('/foo')
   *   .before(function(file) {
   *     file.content += 'foo';
   *   })
   *   .after(function(file) {
   *     file.content += 'bar';
   *   });
   *
   * router.handle(file)
   *   .then(() => {
   *     assert.equal(file.content, 'foobar');
   *   });
   * ```
   * @name .route
   * @param {string} `pattern`
   * @return {object} Returns a new router instance with handler methods bound to the given pattern.
   * @api public
   */

  route(pattern, options) {
    const router = new this.constructor(options);
    for (const method of this.methods) {
      router[method] = (...fns) => router.handler(method)(pattern, ...fns);
    }
    return router;
  }

  /**
   * Add one or more middleware handler methods. Handler methods may also be
   * added by passing an array of handler names to the constructor on the
   * `handlers` option.
   *
   * ```js
   * router.handlers(['onLoad', 'preRender']);
   * ```
   * @name .handlers
   * @param {string} `methods` Method names
   * @param {object} `options`
   * @return {object} Returns the instance for chaining.
   * @api public
   */

  handlers(methods, options) {
    arrayify(methods).forEach(name => this.handler(name, options));
    return this;
  }

  /**
   * Run a middleware methods on the given `file`.
   *
   * ```js
   * // run a specific method
   * router.handle('onLoad', file)
   *   .then(file => console.log('File:', file))
   *   .catch(console.error);
   *
   * // run multiple methods
   * router.handle('onLoad', file)
   *   .then(file => router.handle('preRender', file))
   *   .catch(console.error);
   *
   * // run all methods
   * router.handle(file)
   *   .then(file => console.log('File:', file))
   *   .catch(console.error);
   * ```
   * @name .handle
   * @param {string|file} `method` The handler method to call on `file`. If the first argument is a file object, all handlers will be called on the file.
   * @param {object} `file` File object
   * @return {Promise}
   * @api public
   */

  async handle(method, file) {
    if (method && typeof method === 'object') return this.all(method);

    if (!this.routes.has(method)) {
      throw new Error(`Router handler "${method}" does not exist`);
    }

    for (const route of this.routes.get(method)) await route.handle(file);
    return file;
  }

  /**
   * Register all handler methods on the given file.
   *
   * ```js
   * router.all(file => {
   *   file.data.title = 'Home';
   * });
   * ```
   * @name .all
   * @param {object} `file` File object
   * @return {Promise}
   * @api public
   */

  async all(file) {
    for (const method of this.methods) await this.handle(method, file);
    return file;
  }

  /**
   * Mix router methods onto the given object.
   *
   * ```js
   * const router = new Router();
   * const obj = {};
   * router.handlers(['before', 'after']);
   * router.mixin(obj);
   * console.log(obj.before) //=> [function]
   * ```
   * @name .mixin
   * @param {object} `target`
   * @return {undefined}
   * @api public
   */

  mixin(target) {
    define(target, 'all', this.all.bind(this));
    for (const name of this.methods) {
      define(target, name, this[name].bind(this));
    }
    return this;
  }
}

function arrayify(val) {
  return val ? Array.isArray(val) ? val : [val] : [];
}

/**
 * Expose `Router`
 */

module.exports = Router;
<|endoftext|>


<commit_before>'use strict';

var BearerToken = require('./bearer');
var Inflector = require('inflected');
var Mutation = require('./mutation');

var REST = {
  index: { endpoint: '/', method: 'get' },
  new: { endpoint: '/', method: 'post' },
  show: { endpoint: '/:id', method: 'get' },
  update: { endpoint: '/:id', method: 'put' },
  delete: { endpoint: '/:id', method: 'delete' }
};

var MethodMatrix = {
  GET: 'read',
  POST: 'create',
  PUT: 'edit',
  DELETE: 'delete'
};

var Routes = function(express, DS) {
  var Builder = { express: express };
  var middleware = [];
  var controllers = [];
  var DS = {};
  var Scopes = {};
  var Instance = {};
  var ErrorHandler = require('./errors');

  Builder.mount = function(models, instanceObj) {
    DS = models;
    Instance = instanceObj;

    for (var i = 0; i < controllers.length; i++) {
      Builder.route(controllers[i](DS, Mutation(DS, Instance)));
    }

    express.use(ErrorHandler);
  };

  Builder.addErrorHandler = function(func) {
    ErrorHandler = func;
  };

  Builder.addController = function(controller) {
    controllers.push(controller);
  };

  Builder.registerMiddleware = function(func) {
    middleware.push(func);
  };

  Builder.mixInController = function(spec, action, rest, params) {
    return function(req, res, next) {
      var route = Inflector.singularize(Inflector.camelize(req.route.path.split('/')[1]));
      var resource = params.parent ? params.parent.resource : route;
      var locator = params.parent ? params.parent.fieldName + '._id' : '_id';

      req.controller = {
        spec: spec,
        action: action,
        permissions: Instance.scope[route],
        route: route,
        model: resource,
        locator: locator,
        _rest: rest,
        child: route !== resource
      };

      if (params.parent) req.controller.fieldName = params.parent.fieldName;

      return next();
    };
  };

  Builder.runMiddlewares = function(req, res, next) {
    if (middleware.length < 1) return next();

    for (var i = 0; i < middleware.length; i++) {
      middleware[i](req, res, next);
    }
  };

  // Sets an individual route
  Builder.route = function(controller) {
    var params = {};

    if (controller._parent) params.parent = controller._parent;

    controller._expose.forEach(function(el, i, arr) {
      if (typeof el === 'object') Builder.customRoute(controller._verb, el, controller[el.name], params);
      if (typeof el === 'string') Builder.restRoute(controller._verb, el, controller[el], params);
    });
  };

  // Handles a non-RESTful controller method
  Builder.customRoute = function(verb, spec, action, params) {
    if (!spec || !action) return;

    var method = spec.method;
    var endpoint = '/' + verb;

    if (spec.endpoint !== '/') endpoint += '/' + spec.endpoint;

    express[method](
      endpoint,
      Builder.mixInController(spec, action, false, params),
      BearerToken.serialize,
      Builder.findUser,
      Builder.resourceQuery,
      Builder.runQuery,
      Builder.catchScope,
      Builder.filterAllowedFields,
      Builder.runMiddlewares,
      action.responder
    );
  };

  // Handles a RESTful controller method
  Builder.restRoute = function(verb, name, action, params) {
    if (!REST[name] || !action) return;

    var method = REST[name].method;
    var endpoint = '/' + verb;

    if (REST[name].endpoint !== '/') endpoint += REST[name].endpoint;

    express[method](
      endpoint,
      Builder.mixInController({ verb: verb, name: name }, action, true, params),
      BearerToken.serialize,
      Builder.findUser,
      Builder.resourceQuery,
      Builder.runQuery,
      Builder.catchScope,
      Builder.filterAllowedFields,
      Builder.runMiddlewares,
      action.responder
    );
  };

  Builder.findUser = function(req, res, next) {
    if (!req.bearerToken) return next();

    var User = DS[Instance.scopable.model];
    var query = User.findOne({ _id: req.bearerToken.user });

    query.lean().exec(function(err, user) {
      if (err) return next(err);

      req.user = user;
      return next();
    });
  };

  Builder.catchScope = function(req, res, next) {
    var ownership = false;
    var permissions = req.controller.permissions[MethodMatrix[req.method]] || req.controller.permissions;

    req.caughtScope = '*';

    if (req.user) {
      var userScopes = req.user[Instance.scopable.field];
      if (['index', 'new'].indexOf(req.controller.spec.name) === -1) ownership = Builder._checkForOwnership(req);
      req.caughtScope = (ownership) ? 'owner' : Builder._highestScope(permissions, userScopes);
    }

    if (permissions === true || permissions[req.caughtScope] === true) {
      req.allowedFields = true;
      return next();
    } else if (Array.isArray(permissions)) {
      req.allowedFields = permissions;
      return next();
    } else if (Array.isArray(permissions[req.caughtScope])) {
      req.allowedFields = permissions[req.caughtScope];
      return next();
    } else if (!req.controller._rest && ownership) {
      req.allowedFields = true;
      return next();
    }

    // The user is not authorized to see this resource
    return next({ stack: 'auth', translation: 'api.error.auth.insufficient_privilege', message: 'Insufficient privileges for that' });
  };

  Builder.resourceQuery = function(req, res, next) {
    req.searchParams = {};

    if (!req.params.id && req.controller.permissions.searchableBy) {
      var allowed = req.controller.permissions.searchableBy;

      for (var i = 0; i < allowed.length; i++) {
        if (req.parsedQuery[allowed[i]]) req.searchParams[allowed[i]] = req.parsedQuery[allowed[i]];
      }
    }

    return next();
  };

  Builder.runQuery = function(req, res, next) {
    var Model = DS[req.controller.model];
    req.rawResources = {};

    if (req.params.id && !req.controller.child) {
      var q = Model.findById(req.params.id);

      q.lean().exec(function(err, result) {
        if (err) return next(err);

        req.rawResources = result;
        return next();
      });
    } else if (req.params.id && req.controller.child) {
      var search = {};
      search[req.controller.locator] = req.params.id;

      var q = Model.findOne(search);

      q.lean().exec(function(err, result) {
        if (err) return next(err);
        if (result === null) return next({ message: 'not found' });

        var resource = result[req.controller.fieldName];

        if (Array.isArray(resource)) {
          for (var i = 0; i < resource.length; i++) {
            if (req.params.id === resource[i]._id.toString()) resource = resource[i];
          }
        }

        req.rawResources = resource;
        return next();
      });

    } else if (!req.params.id && req.method === 'GET' && !req.controller.child) {
      var q = Model.find(req.searchParams);
      var count = Model.count(req.searchParams);

      if (req.query.page) {
        var perPage = parseInt(req.query.perPage) || 20;
        q.skip((parseInt(req.query.page) * perPage) - perPage);
        q.limit(perPage);
      } else {
        q.limit(req.query.limit || 20);
      }

      if (req.query.sort) q.sort(req.query.sort);

      q.lean().exec(function(err, result) {
        if (err) return next(err);

        count.lean().exec(function(err, counter) {
          if (err) return next(err);

          req.rawResources = result;
          req.rawResourcesCount = counter;
          return next();
        });
      });
    } else if (!req.params.id && req.method === 'GET' && req.controller.child) {
      var projection = {};
      var fields = Object.keys(DS[req.controller.route].schema.paths);

      for (var i = 0; i < fields.length; i++) {
        projection[fields[i]] = '$' + req.controller.fieldName + '.' + fields[i];
      }

      var query = [
        { $match: req.searchParams },
        { $unwind: '$' + req.controller.fieldName },
        { $match: req.searchParams },
        { $project: projection }
      ];

      var agg = Model.aggregate(query);

      agg.exec(function(err, result) {
        if (err) return next(err);

        var resource = [];

        if (req.query.page) {
          var perPage = parseInt(req.query.perPage) || 20;
          var skip = (parseInt(req.query.page) * perPage) - perPage;
          resource = result.slice(skip, skip + perPage);
        } else {
          resource = result.slice(0, 19);
        }

        console.log(result);

        req.rawResources = resource;
        req.rawResourcesCount = result.length;
        return next();
      });
    } else {
      return next();
    }
  };

  Builder.filterAllowedFields = function(req, res, next) {
    if (Object.keys(req.rawResources).length === 0) return next();

    if (req.allowedFields !== true) req.allowedFields.push('_id');

    if (Array.isArray(req.rawResources)) {
      req.resource = [];
      for (var i = 0; i < req.rawResources.length; i++) {
        req.resource.push(Builder.filterFromResource(req.rawResources[i], req.allowedFields));
      }
    } else {
      req.resource = Builder.filterFromResource(req.rawResources, req.allowedFields);
    }

    return next();
  };

  Builder.filterFromResource = function(resource, allowed) {
    if (allowed === true) return resource;
    var safeResource = {};

    for (var i = 0; i < allowed.length; i++) {
      safeResource[allowed[i]] = resource[allowed[i]];
    }

    return safeResource;
  };

  Builder._checkForOwnership = function(req) {
    if (Object.keys(req.rawResources).length === 0) return false;

    var model = req.controller.model;
    var permissions = req.controller.permissions;

    if (!permissions.owners || permissions.owners.length < 1) return false;
    if (Array.isArray(req.rawResources)) return false;
    if (!req.user) return false;

    for (var i = 0; i < permissions.owners.length; i++) {
      if (typeof req.rawResources[permissions.owners[i]] === 'undefined') return false;
      if (typeof req.user._id === 'undefined') return false;

      if (req.rawResources[permissions.owners[i]].toString() === req.user._id.toString()) return true;
    }

    return false;
  };

  Builder._highestScope = function(permissions, scopes) {
    if (typeof permissions === 'undefined') return '*';

    var highest = 0;
    var fieldCount = 0;

    scopes.unshift('*');

    for (var i = 0; i < scopes.length; i++) {
      if (permissions === true || Array.isArray(permissions)) {
        return '*';
      } else if (permissions[scopes[i]] === true) {
        return scopes[i];
      } else if (Array.isArray(permissions[scopes[i]]) && (fieldCount < permissions[scopes[i]].length)) {
        highest = i;
        fieldCount = permissions[scopes[i]].length;
      }
    }

    return scopes[highest];
  };

  return Builder;

};

module.exports = Routes;
<commit_msg>fixing issue where blank queries returned no envelope<commit_after>'use strict';

var BearerToken = require('./bearer');
var Inflector = require('inflected');
var Mutation = require('./mutation');

var REST = {
  index: { endpoint: '/', method: 'get' },
  new: { endpoint: '/', method: 'post' },
  show: { endpoint: '/:id', method: 'get' },
  update: { endpoint: '/:id', method: 'put' },
  delete: { endpoint: '/:id', method: 'delete' }
};

var MethodMatrix = {
  GET: 'read',
  POST: 'create',
  PUT: 'edit',
  DELETE: 'delete'
};

var Routes = function(express, DS) {
  var Builder = { express: express };
  var middleware = [];
  var controllers = [];
  var DS = {};
  var Scopes = {};
  var Instance = {};
  var ErrorHandler = require('./errors');

  Builder.mount = function(models, instanceObj) {
    DS = models;
    Instance = instanceObj;

    for (var i = 0; i < controllers.length; i++) {
      Builder.route(controllers[i](DS, Mutation(DS, Instance)));
    }

    express.use(ErrorHandler);
  };

  Builder.addErrorHandler = function(func) {
    ErrorHandler = func;
  };

  Builder.addController = function(controller) {
    controllers.push(controller);
  };

  Builder.registerMiddleware = function(func) {
    middleware.push(func);
  };

  Builder.mixInController = function(spec, action, rest, params) {
    return function(req, res, next) {
      var route = Inflector.singularize(Inflector.camelize(req.route.path.split('/')[1]));
      var resource = params.parent ? params.parent.resource : route;
      var locator = params.parent ? params.parent.fieldName + '._id' : '_id';

      req.controller = {
        spec: spec,
        action: action,
        permissions: Instance.scope[route],
        route: route,
        model: resource,
        locator: locator,
        _rest: rest,
        child: route !== resource
      };

      if (params.parent) req.controller.fieldName = params.parent.fieldName;

      return next();
    };
  };

  Builder.runMiddlewares = function(req, res, next) {
    if (middleware.length < 1) return next();

    for (var i = 0; i < middleware.length; i++) {
      middleware[i](req, res, next);
    }
  };

  // Sets an individual route
  Builder.route = function(controller) {
    var params = {};

    if (controller._parent) params.parent = controller._parent;

    controller._expose.forEach(function(el, i, arr) {
      if (typeof el === 'object') Builder.customRoute(controller._verb, el, controller[el.name], params);
      if (typeof el === 'string') Builder.restRoute(controller._verb, el, controller[el], params);
    });
  };

  // Handles a non-RESTful controller method
  Builder.customRoute = function(verb, spec, action, params) {
    if (!spec || !action) return;

    var method = spec.method;
    var endpoint = '/' + verb;

    if (spec.endpoint !== '/') endpoint += '/' + spec.endpoint;

    express[method](
      endpoint,
      Builder.mixInController(spec, action, false, params),
      BearerToken.serialize,
      Builder.findUser,
      Builder.resourceQuery,
      Builder.runQuery,
      Builder.catchScope,
      Builder.filterAllowedFields,
      Builder.runMiddlewares,
      action.responder
    );
  };

  // Handles a RESTful controller method
  Builder.restRoute = function(verb, name, action, params) {
    if (!REST[name] || !action) return;

    var method = REST[name].method;
    var endpoint = '/' + verb;

    if (REST[name].endpoint !== '/') endpoint += REST[name].endpoint;

    express[method](
      endpoint,
      Builder.mixInController({ verb: verb, name: name }, action, true, params),
      BearerToken.serialize,
      Builder.findUser,
      Builder.resourceQuery,
      Builder.runQuery,
      Builder.catchScope,
      Builder.filterAllowedFields,
      Builder.runMiddlewares,
      action.responder
    );
  };

  Builder.findUser = function(req, res, next) {
    if (!req.bearerToken) return next();

    var User = DS[Instance.scopable.model];
    var query = User.findOne({ _id: req.bearerToken.user });

    query.lean().exec(function(err, user) {
      if (err) return next(err);

      req.user = user;
      return next();
    });
  };

  Builder.catchScope = function(req, res, next) {
    var ownership = false;
    var permissions = req.controller.permissions[MethodMatrix[req.method]] || req.controller.permissions;

    req.caughtScope = '*';

    if (req.user) {
      var userScopes = req.user[Instance.scopable.field];
      if (['index', 'new'].indexOf(req.controller.spec.name) === -1) ownership = Builder._checkForOwnership(req);
      req.caughtScope = (ownership) ? 'owner' : Builder._highestScope(permissions, userScopes);
    }

    if (permissions === true || permissions[req.caughtScope] === true) {
      req.allowedFields = true;
      return next();
    } else if (Array.isArray(permissions)) {
      req.allowedFields = permissions;
      return next();
    } else if (Array.isArray(permissions[req.caughtScope])) {
      req.allowedFields = permissions[req.caughtScope];
      return next();
    } else if (!req.controller._rest && ownership) {
      req.allowedFields = true;
      return next();
    }

    // The user is not authorized to see this resource
    return next({ stack: 'auth', translation: 'api.error.auth.insufficient_privilege', message: 'Insufficient privileges for that' });
  };

  Builder.resourceQuery = function(req, res, next) {
    req.searchParams = {};

    if (!req.params.id && req.controller.permissions.searchableBy) {
      var allowed = req.controller.permissions.searchableBy;

      for (var i = 0; i < allowed.length; i++) {
        if (req.parsedQuery[allowed[i]]) req.searchParams[allowed[i]] = req.parsedQuery[allowed[i]];
      }
    }

    return next();
  };

  Builder.runQuery = function(req, res, next) {
    var Model = DS[req.controller.model];
    req.rawResources = {};

    if (req.params.id && !req.controller.child) {
      var q = Model.findById(req.params.id);

      q.lean().exec(function(err, result) {
        if (err) return next(err);

        req.rawResources = result;
        return next();
      });
    } else if (req.params.id && req.controller.child) {
      var search = {};
      search[req.controller.locator] = req.params.id;

      var q = Model.findOne(search);

      q.lean().exec(function(err, result) {
        if (err) return next(err);
        if (result === null) return next({ message: 'not found' });

        var resource = result[req.controller.fieldName];

        if (Array.isArray(resource)) {
          for (var i = 0; i < resource.length; i++) {
            if (req.params.id === resource[i]._id.toString()) resource = resource[i];
          }
        }

        req.rawResources = resource;
        return next();
      });

    } else if (!req.params.id && req.method === 'GET' && !req.controller.child) {
      var q = Model.find(req.searchParams);
      var count = Model.count(req.searchParams);

      if (req.query.page) {
        var perPage = parseInt(req.query.perPage) || 20;
        q.skip((parseInt(req.query.page) * perPage) - perPage);
        q.limit(perPage);
      } else {
        q.limit(req.query.limit || 20);
      }

      if (req.query.sort) q.sort(req.query.sort);

      q.lean().exec(function(err, result) {
        if (err) return next(err);

        count.lean().exec(function(err, counter) {
          if (err) return next(err);

          req.rawResources = result;
          req.rawResourcesCount = counter;
          return next();
        });
      });
    } else if (!req.params.id && req.method === 'GET' && req.controller.child) {
      var projection = {};
      var fields = Object.keys(DS[req.controller.route].schema.paths);

      for (var i = 0; i < fields.length; i++) {
        projection[fields[i]] = '$' + req.controller.fieldName + '.' + fields[i];
      }

      var query = [
        { $match: req.searchParams },
        { $unwind: '$' + req.controller.fieldName },
        { $match: req.searchParams },
        { $project: projection }
      ];

      var agg = Model.aggregate(query);

      agg.exec(function(err, result) {
        if (err) return next(err);

        var resource = [];

        if (req.query.page) {
          var perPage = parseInt(req.query.perPage) || 20;
          var skip = (parseInt(req.query.page) * perPage) - perPage;
          resource = result.slice(skip, skip + perPage);
        } else {
          resource = result.slice(0, 19);
        }

        req.rawResources = resource;
        req.rawResourcesCount = result.length;
        return next();
      });
    } else {
      return next();
    }
  };

  Builder.filterAllowedFields = function(req, res, next) {
    if (Object.keys(req.rawResources).length === 0) {
      req.resource = [];
      return next();
    }

    if (req.allowedFields !== true) req.allowedFields.push('_id');

    if (Array.isArray(req.rawResources)) {
      req.resource = [];
      for (var i = 0; i < req.rawResources.length; i++) {
        req.resource.push(Builder.filterFromResource(req.rawResources[i], req.allowedFields));
      }
    } else {
      req.resource = Builder.filterFromResource(req.rawResources, req.allowedFields);
    }

    return next();
  };

  Builder.filterFromResource = function(resource, allowed) {
    if (allowed === true) return resource;
    var safeResource = {};

    for (var i = 0; i < allowed.length; i++) {
      safeResource[allowed[i]] = resource[allowed[i]];
    }

    return safeResource;
  };

  Builder._checkForOwnership = function(req) {
    if (Object.keys(req.rawResources).length === 0) return false;

    var model = req.controller.model;
    var permissions = req.controller.permissions;

    if (!permissions.owners || permissions.owners.length < 1) return false;
    if (Array.isArray(req.rawResources)) return false;
    if (!req.user) return false;

    for (var i = 0; i < permissions.owners.length; i++) {
      if (typeof req.rawResources[permissions.owners[i]] === 'undefined') return false;
      if (typeof req.user._id === 'undefined') return false;

      if (req.rawResources[permissions.owners[i]].toString() === req.user._id.toString()) return true;
    }

    return false;
  };

  Builder._highestScope = function(permissions, scopes) {
    if (typeof permissions === 'undefined') return '*';

    var highest = 0;
    var fieldCount = 0;

    scopes.unshift('*');

    for (var i = 0; i < scopes.length; i++) {
      if (permissions === true || Array.isArray(permissions)) {
        return '*';
      } else if (permissions[scopes[i]] === true) {
        return scopes[i];
      } else if (Array.isArray(permissions[scopes[i]]) && (fieldCount < permissions[scopes[i]].length)) {
        highest = i;
        fieldCount = permissions[scopes[i]].length;
      }
    }

    return scopes[highest];
  };

  return Builder;

};

module.exports = Routes;
<|endoftext|>


<commit_before>'use strict';

var pathRegexp = require('path-to-regexp');
var url = new URL('./', self.location);
var baseUrl = url.protocol + '//' + url.host;
var basePath = url.pathname;

var Route = function(method, path, handler) {
  // The URL() constructor can't parse express-style routes as they are not
  // valid urls. This means we have to manually manipulate relative urls into
  // absolute ones. This check is extremely naive but implementing a tweaked
  // version of the full algorithm seems like overkill
  // (https://url.spec.whatwg.org/#concept-basic-url-parser)
  if (!(path.indexOf('http://') === 0 || path.indexOf('https://') === 0)) {
    if (path.indexOf('/') !== 0) {
      path = basePath + path;
    }
    path = baseUrl + path;
  }

  this.method = method;
  this.keys = [];
  this.regexp = pathRegexp(path, this.keys);
  this.handler = handler;
};

Route.prototype.makeHandler = function(url) {
    var match = this.regexp.exec(url);
    var values = {};
    this.keys.forEach(function(key, index) {
      values[key.name] = match[index + 1];
    });
    return function(request) {
      return this.handler(request, values);
    }.bind(this);
};

var Router = function() {
  this.routes = {};
  this.default = null;
};

Router.prototype.get = function(path, handler) {
  return this.add('get', path, handler);
};

Router.prototype.post = function(path, handler) {
  return this.add('post', path, handler);
};

Router.prototype.put = function(path, handler) {
  return this.add('put', path, handler);
};

Router.prototype.delete = function(path, handler) {
  return this.add('delete', path, handler);
};

Router.prototype.head = function(path, handler) {
  return this.add('head', path, handler);
};

Router.prototype.any = function(path, handler) {
  return this.add('any', path, handler);
};

Router.prototype.add = function(method, path, handler) {
  this.routes[method] = this.routes[method] || {};
  this.routes[method][path] = new Route(method.toLowerCase(), path, handler);
};

Router.prototype.matchMethod = function(method, url) {
  var routes = this.routes[method.toLowerCase()];
  if (!routes) {
    return null;
  }
  var match, route;
  var paths = Object.keys(routes);
  for (var i = 0; i < paths.length; i++) {
    route = routes[paths[i]];
    match = route.regexp.exec(url);
    if (match) {
      return route.makeHandler(url);
    }
  }
  return null;
};

Router.prototype.match = function(request) {
  return this.matchMethod(request.method, request.url) || this.matchMethod('any', request.url);
};

module.exports = new Router();
<commit_msg>Fixed indentation, closes #13<commit_after>'use strict';

var pathRegexp = require('path-to-regexp');
var url = new URL('./', self.location);
var baseUrl = url.protocol + '//' + url.host;
var basePath = url.pathname;

var Route = function(method, path, handler) {
  // The URL() constructor can't parse express-style routes as they are not
  // valid urls. This means we have to manually manipulate relative urls into
  // absolute ones. This check is extremely naive but implementing a tweaked
  // version of the full algorithm seems like overkill
  // (https://url.spec.whatwg.org/#concept-basic-url-parser)
  if (!(path.indexOf('http://') === 0 || path.indexOf('https://') === 0)) {
    if (path.indexOf('/') !== 0) {
      path = basePath + path;
    }
    path = baseUrl + path;
  }

  this.method = method;
  this.keys = [];
  this.regexp = pathRegexp(path, this.keys);
  this.handler = handler;
};

Route.prototype.makeHandler = function(url) {
  var match = this.regexp.exec(url);
  var values = {};
  this.keys.forEach(function(key, index) {
    values[key.name] = match[index + 1];
  });
  return function(request) {
    return this.handler(request, values);
  }.bind(this);
};

var Router = function() {
  this.routes = {};
  this.default = null;
};

Router.prototype.get = function(path, handler) {
  return this.add('get', path, handler);
};

Router.prototype.post = function(path, handler) {
  return this.add('post', path, handler);
};

Router.prototype.put = function(path, handler) {
  return this.add('put', path, handler);
};

Router.prototype.delete = function(path, handler) {
  return this.add('delete', path, handler);
};

Router.prototype.head = function(path, handler) {
  return this.add('head', path, handler);
};

Router.prototype.any = function(path, handler) {
  return this.add('any', path, handler);
};

Router.prototype.add = function(method, path, handler) {
  this.routes[method] = this.routes[method] || {};
  this.routes[method][path] = new Route(method.toLowerCase(), path, handler);
};

Router.prototype.matchMethod = function(method, url) {
  var routes = this.routes[method.toLowerCase()];
  if (!routes) {
    return null;
  }
  var match, route;
  var paths = Object.keys(routes);
  for (var i = 0; i < paths.length; i++) {
    route = routes[paths[i]];
    match = route.regexp.exec(url);
    if (match) {
      return route.makeHandler(url);
    }
  }
  return null;
};

Router.prototype.match = function(request) {
  return this.matchMethod(request.method, request.url) || this.matchMethod('any', request.url);
};

module.exports = new Router();
<|endoftext|>


<commit_before>var http = require('http'),
    qsparse = require('./querystring').parse,
    urljoin = require('./path-join'),
    util = require('util');

var pathRegex = require('path-to-regexp');

var EMPTY_PARAMS = {},
    STATUS_CODES = http.STATUS_CODES,
    ROUTES_MATCH_ALL = [ '' ],
    METHODS;

if (http.METHODS)
  METHODS = http.METHODS;
else {
  METHODS = [
    'DELETE',
    'GET',
    'HEAD',
    'POST',
    'PUT',
    /* PATHOLOGICAL */
    'CONNECT',
    'OPTIONS',
    'TRACE',
    /* WEBDAV */
    'COPY',
    'LOCK',
    'MKCOL',
    'MOVE',
    'PROPFIND',
    'PROPPATCH',
    'SEARCH',
    'UNLOCK',
    /* SUBVERSION */
    'REPORT',
    'MKACTIVITY',
    'CHECKOUT',
    'MERGE',
    /* UPNP */
    'MSEARCH',
    'NOTIFY',
    'SUBSCRIBE',
    'UNSUBSCRIBE',
    /* RFC-5789 */
    'PATCH',
    'PURGE'
  ].sort();
}
METHODS = METHODS.map(function(method) { return method.toLowerCase(); });

function Router(opts) {
  if (!(this instanceof Router))
    return new Router(opts);

  var self = this;

  // [ regexp, pathkeys, handler(s) ]
  this._stack = [];

  this._paramFuncs = {};
  this._mounted = false;
  this._optimized = false;

  this.path = '/';

  this.handler = function routerHandlerWrap(req, res, cb) {
    self.handle(req, res, cb);
  };
}

Router.prototype.handle = function routerReqHandler(req, res, cb) {
  var stack = this._stack,
      stacklen = stack.length,
      ptr = 0,
      subPtr = 0,
      paramPtr = 0,
      paramsCache = {},
      paramFuncs = this._paramFuncs,
      urlpath = req.url,
      qm,
      pathname;

  //console.dir(this._stack);
  //var reqid = ''+Date.now();

  // req/res decorations
  if (!req.router) {
    qm = urlpath.indexOf('?');
    if (qm > -1) {
      req.path = urlpath.substring(0, qm);
      if (qm === urlpath.length - 1)
        req.query = {};
      else
        req.query = qsparse(urlpath.substring(qm + 1));
    } else {
      req.path = urlpath;
      req.query = {};
    }
  }
  pathname = req.path;
  req.router = res.router = this;
  // end req/res decorations

  function next(err) {
    var curmw,
        m,
        error,
        method = req.method,
        isHead = (method === 'HEAD');

    if (err !== undefined && err !== null) {
      if (util.isError(err))
        error = err;
      else if (typeof err === 'string') {
        error = new Error(err);
        error.code = err.code || this.DEFAULT_ERROR_STATUS;
      } else if (typeof err === 'number' && err >= 400 && err < 600) {
        error = new Error(method
                          + ' '
                          + pathname
                          + ' '
                          + (STATUS_CODES[err] || 'Unknown Error'));
        error.code = err;
      } else {
        error = new Error(method + ' ' + pathname + ' Unknown Error');
        error.code = this.DEFAULT_ERROR_STATUS;
      }
    }

    // TODO: optimize for compressed case to avoid having to execute the same
    // route regexp for every handler in the route's handlers array
    for (; ptr < stacklen; ++ptr, subPtr = 0, paramPtr = 0) {
      //console.log(reqid, 'ptr', ptr, 'subPtr', subPtr, 'stacklen', stacklen);
      curmw = stack[ptr];
      if (m = curmw[0].exec(pathname)) {
        var handlers = curmw[2],
            isMultiHandler = false,
            multiLen,
            handler;

        if (handlerMatches(handlers, method, error, isHead)) {
          handler = (typeof handlers === 'function'
                     ? handlers
                     : handlers.handler);
        } else if (handlers instanceof Array
                   && subPtr < (multiLen = handlers.length)) {
          // complex case, multiple handlers for this route path
          for (; subPtr < multiLen; ++subPtr) {
            if (handlerMatches(handlers[subPtr], method, error, isHead)) {
              handler = handlers[subPtr];
              if (typeof handler === 'object')
                handler = handler.handler;
              isMultiHandler = true;
              break;
            }
          }
        }

        if (!handler)
          continue;

        // check for `router.param('foo', cb);` calls before calling route
        // handler
        if (curmw[1] && curmw[1].length) {
          var resrc = curmw[0].toString();
          req.params = (paramsCache[resrc]
                        || (paramsCache[resrc] = makeParams(m, curmw[1])));
          var paramKeys = Object.keys(req.params);
          for (var lenk = paramKeys.length, fn; paramPtr < lenk; ++paramPtr) {
            if (fn = paramFuncs[paramKeys[paramPtr]])
              return fn(req, res, next, req.params[paramKeys[paramPtr++]]);
          }
        } else
          req.params = EMPTY_PARAMS;

        if (isMultiHandler)
          ++subPtr;
        else
          ++ptr;

        try {
          if (error === undefined)
            return handler(req, res, next);
          else
            return handler(error, req, res, next);
        } catch (ex) {
          error = ex;
          error.code = 500;
        }
      }
    }
    if (ptr === stacklen) {
      if (cb)
        cb(error);
      else if (error === undefined)
        res.end(method + ' ' + pathname + ' ' + STATUS_CODES[res.statusCode = 404]);
      else {
        res.statusCode = error.code;
        res.end(error.message);
      }
    }
  }

  next();
};
Router.prototype.DEFAULT_ERROR_STATUS = 500;

function handlerMatches(handler, method, error, isHead) {
  var ret = false,
      fn;
  if (typeof handler === 'function')
    fn = handler;
  else if (!(handler instanceof Array)
           && (method === handler.method
               || (isHead && handler.method === 'GET')))
    fn = handler.handler;

  if (fn && ((error === undefined && fn.length < 4)
             || (error !== undefined && fn.length === 4)))
    ret = true;

  return ret;
}

Router.prototype.use = function routerUse(route) {
  var handlersStart = 1,
      handlersEnd = arguments.length,
      routes = route,
      method;

  if (arguments.length > 2
      && typeof arguments[arguments.length - 1] === 'string') {
    method = arguments[arguments.length - 1].toUpperCase();
    --handlersEnd;
  }

  if (route instanceof Router)
    throw new Error('You must specify string path(s) when mounting a Router');
  else if (typeof route === 'function') {
    handlersStart = 0;
    routes = ROUTES_MATCH_ALL;
  }

  if (!Array.isArray(routes))
    routes = [ routes ];

  for (var i = 0, len = routes.length, fullPath, regex, keys; i < len; ++i) {
    if (util.isRegExp(routes[i])) {
      keys = null;
      regex = routes[i];
    } else {
      keys = [];
      if (routes === ROUTES_MATCH_ALL) {
        fullPath = this.path;
        regex = pathRegex(fullPath, keys, { end: false });
      } else {
        fullPath = urljoin(this.path, routes[i]);
        regex = pathRegex(fullPath, keys);
      }
    }

    for (var h = handlersStart; h < handlersEnd; ++h) {
      var handlerfn = arguments[h];
      if (typeof handlerfn !== 'function' && !(handlerfn instanceof Router))
        continue;
      else if (handlerfn instanceof Router) {
        if (keys === null)
          throw new Error('You must specify a string path when mounting a Router');
        else if (handlerfn._mounted)
          throw new Error('Cannot mount a Router in multiple places');
        handlerfn.path = fullPath;
        handlerfn._mounted = true;
        handlerfn = handlerfn.handler;
      }

      this._stack.push([
        regex,
        keys,
        (method ? { method: method, handler: handlerfn } : handlerfn)
      ]);
    }
  }

  return this;
};

Router.prototype.all = Router.prototype.use;

METHODS.forEach(function(method) {
  Router.prototype[method] = function methodRoute(route, handler) {
    switch (arguments.length) {
      case 1:
      case 2:
        return this.use(route, handler, method);

      case 3:
        return this.use(route, handler, arguments[2], method);

      case 4:
        return this.use(route, handler, arguments[2], arguments[3], method);

      case 5:
        return this.use(route,
                        handler,
                        arguments[2],
                        arguments[3],
                        arguments[4],
                        method);

      default:
        var args = new Array(arguments.length + 1);
        for (var i = 0, len = args.length; i < len; ++i)
          args[i] = arguments[i];
        args[i] = method;
        return this.use.apply(this, args);
    }
  };
});

Router.prototype.param = function(name, cb) {
  if (typeof name !== 'string')
    throw new Error('Param name is required');
  if (typeof cb === 'function')
    this._paramFuncs[name] = cb;
};

Router.prototype.route = function(path, opts) {
  var router = new Router(opts);
  this.use(path, router);
  return router;
};

Router.prototype.compress = function() {
  // Call this to compress the current middleware stack. Specifically it
  // combines route handlers for the same route paths to avoid having to call
  // the same regular expressions multiple times.

  // This should only be called before you start serving requests because it
  // modifies the middleware stack and that could mess things up if a request
  // is currently in progress.

  if (this._optimized)
    return;

  var general_path = pathRegex(this.path, [], { end: false });

  var stack = this._stack,
      newStack = [],
      isGeneral = false,
      len = stack.length,
      i,
      layer;

  // first pass, collecting unique non-general route paths
  for (i = 0; i < len; ++i) {
    isGeneral = (regexpsEqual(stack[i][0], general_path)
                 && typeof stack[i][2] === 'function');
    if (!isGeneral) {
      if (!getNewPath(stack[i][0]))
        newStack.push(stack[i]);
    }
  }

  if (newStack.length) {
    // second pass, copying general route handlers to non-general routes
    for (i = 0; i < len; ++i) {
      isGeneral = (regexpsEqual(stack[i][0], general_path)
                   && typeof stack[i][2] === 'function');
      if (isGeneral) {
        // append to all non-general routes
        var handler = stack[i][2];
        for (var j = 0, newlen = newStack.length; j < newlen; ++j) {
          if (newStack[j][2] instanceof Array)
            newStack[j][2].push(handler);
          else
            newStack[j][2] = [ newStack[j][2], handler ];
        }
      } else {
        // we have a non-general route to append
        layer = getNewPath(stack[i][0]);
        if (layer[2] === stack[i][2]) {
          // this was the original route we captured in the first pass, so skip
          // it
          continue;
        }
        if (layer[2] instanceof Array)
          layer[2].push(stack[i][2]);
        else
          layer[2] = [ layer[2], stack[i][2] ];
      }
    }
  } else if (len) {
    // the stack consists only of general middleware, so just keep combine
    // entire stack into one layer
    newStack.push(layer = stack[0]);
    for (i = 1; i < len; ++i) {
      if (layer[2] instanceof Array)
        layer[2].push(stack[i][2]);
      else
        layer[2] = [ layer[2], stack[i][2] ];
    }
  }

  this._stack = newStack;

  this._optimized = true;

  function getNewPath(path) {
    for (var j = 0, newlen = newStack.length; j < newlen; ++j)
      if (regexpsEqual(path, newStack[j][0]))
        return newStack[j];
  }
};

module.exports = Router;

function decodeParam(val) {
  if (typeof val !== 'string')
    return val;

  try {
    return decodeURIComponent(val);
  } catch (e) {
    return false;
  }
}

function makeParams(m, keys) {
  if (!keys)
    return (m && m.length > 1 && m.slice(1, m.length));
  else if (m.length <= 1)
    return;

  var params = {};

  if (m.length > 1)
    params = {};

  for (var i = 1, len = m.length, key, val; i < len; ++i) {
    key = keys[i - 1];
    val = decodeParam(m[i]);
    if (val === false)
      params[key.name] = val;
    else
      params[key.name] = m[i];
  }

  return params;
}

function regexpsEqual(re1, re2) {
  return (re1.source === re2.source
          && re1.global === re2.global
          && re1.ignoreCase === re2.ignoreCase
          && re1.multiline === re2.multiline);
}
<commit_msg>router: style changes<commit_after>var http = require('http'),
    qsparse = require('./querystring').parse,
    urljoin = require('./path-join'),
    util = require('util');

var pathRegex = require('path-to-regexp');

var EMPTY_PARAMS = {},
    STATUS_CODES = http.STATUS_CODES,
    ROUTES_MATCH_ALL = [ '' ],
    METHODS;

if (http.METHODS)
  METHODS = http.METHODS;
else {
  METHODS = [
    'DELETE',
    'GET',
    'HEAD',
    'POST',
    'PUT',
    /* PATHOLOGICAL */
    'CONNECT',
    'OPTIONS',
    'TRACE',
    /* WEBDAV */
    'COPY',
    'LOCK',
    'MKCOL',
    'MOVE',
    'PROPFIND',
    'PROPPATCH',
    'SEARCH',
    'UNLOCK',
    /* SUBVERSION */
    'REPORT',
    'MKACTIVITY',
    'CHECKOUT',
    'MERGE',
    /* UPNP */
    'MSEARCH',
    'NOTIFY',
    'SUBSCRIBE',
    'UNSUBSCRIBE',
    /* RFC-5789 */
    'PATCH',
    'PURGE'
  ].sort();
}
METHODS = METHODS.map(function(method) { return method.toLowerCase(); });

function Router(opts) {
  if (!(this instanceof Router))
    return new Router(opts);

  var self = this;

  // [ regexp, pathkeys, handler(s) ]
  this._stack = [];

  this._paramFuncs = {};
  this._mounted = false;
  this._optimized = false;

  this.path = '/';

  this.handler = function routerHandlerWrap(req, res, cb) {
    self.handle(req, res, cb);
  };
}

Router.prototype.handle = function routerReqHandler(req, res, cb) {
  var stack = this._stack,
      stacklen = stack.length,
      ptr = 0,
      subPtr = 0,
      paramPtr = 0,
      paramsCache = {},
      paramFuncs = this._paramFuncs;

  //console.dir(this._stack);
  //var reqid = ''+Date.now();

  // req/res decorations
  if (!req.router) {
    var urlpath = req.url,
        qm = urlpath.indexOf('?');
    if (qm > -1) {
      req.path = urlpath.substring(0, qm);
      if (qm === urlpath.length - 1)
        req.query = {};
      else
        req.query = qsparse(urlpath.substring(qm + 1));
    } else {
      req.path = urlpath;
      req.query = {};
    }
  }
  var pathname = req.path;
  req.router = res.router = this;
  // end req/res decorations

  function next(err) {
    var curmw,
        m,
        error,
        method = req.method,
        isHead = (method === 'HEAD');

    if (err !== undefined && err !== null) {
      if (util.isError(err))
        error = err;
      else if (typeof err === 'string') {
        error = new Error(err);
        error.code = err.code || this.DEFAULT_ERROR_STATUS;
      } else if (typeof err === 'number' && err >= 400 && err < 600) {
        error = new Error(method
                          + ' '
                          + pathname
                          + ' '
                          + (STATUS_CODES[err] || 'Unknown Error'));
        error.code = err;
      } else {
        error = new Error(method + ' ' + pathname + ' Unknown Error');
        error.code = this.DEFAULT_ERROR_STATUS;
      }
    }

    // TODO: optimize for compressed case to avoid having to execute the same
    // route regexp for every handler in the route's handlers array
    for (; ptr < stacklen; ++ptr, subPtr = 0, paramPtr = 0) {
      //console.log(reqid, 'ptr', ptr, 'subPtr', subPtr, 'stacklen', stacklen);
      curmw = stack[ptr];
      if (m = curmw[0].exec(pathname)) {
        var handlers = curmw[2],
            isMultiHandler = false,
            multiLen,
            handler;

        if (handlerMatches(handlers, method, error, isHead)) {
          handler = (typeof handlers === 'function'
                     ? handlers
                     : handlers.handler);
        } else if (handlers instanceof Array
                   && subPtr < (multiLen = handlers.length)) {
          // complex case, multiple handlers for this route path
          for (; subPtr < multiLen; ++subPtr) {
            if (handlerMatches(handlers[subPtr], method, error, isHead)) {
              handler = handlers[subPtr];
              if (typeof handler === 'object')
                handler = handler.handler;
              isMultiHandler = true;
              break;
            }
          }
        }

        if (!handler)
          continue;

        // check for `router.param('foo', cb);` calls before calling route
        // handler
        if (curmw[1] && curmw[1].length) {
          var resrc = curmw[0].toString();
          req.params = (paramsCache[resrc]
                        || (paramsCache[resrc] = makeParams(m, curmw[1])));
          var paramKeys = Object.keys(req.params);
          for (var lenk = paramKeys.length, fn; paramPtr < lenk; ++paramPtr) {
            if (fn = paramFuncs[paramKeys[paramPtr]])
              return fn(req, res, next, req.params[paramKeys[paramPtr++]]);
          }
        } else
          req.params = EMPTY_PARAMS;

        if (isMultiHandler)
          ++subPtr;
        else
          ++ptr;

        try {
          if (error === undefined)
            return handler(req, res, next);
          else
            return handler(error, req, res, next);
        } catch (ex) {
          error = ex;
          error.code = 500;
        }
      }
    }
    if (ptr === stacklen) {
      if (cb)
        cb(error);
      else if (error === undefined)
        res.end(method + ' ' + pathname + ' ' + STATUS_CODES[res.statusCode = 404]);
      else {
        res.statusCode = error.code;
        res.end(error.message);
      }
    }
  }

  next();
};
Router.prototype.DEFAULT_ERROR_STATUS = 500;

function handlerMatches(handler, method, error, isHead) {
  var ret = false,
      fn;
  if (typeof handler === 'function')
    fn = handler;
  else if (!(handler instanceof Array)
           && (method === handler.method
               || (isHead && handler.method === 'GET')))
    fn = handler.handler;

  if (fn && ((error === undefined && fn.length < 4)
             || (error !== undefined && fn.length === 4)))
    ret = true;

  return ret;
}

Router.prototype.use = function routerUse(route) {
  var handlersStart = 1,
      handlersEnd = arguments.length,
      routes = route,
      method;

  if (arguments.length > 2
      && typeof arguments[arguments.length - 1] === 'string') {
    method = arguments[arguments.length - 1].toUpperCase();
    --handlersEnd;
  }

  if (route instanceof Router)
    throw new Error('You must specify string path(s) when mounting a Router');
  else if (typeof route === 'function') {
    handlersStart = 0;
    routes = ROUTES_MATCH_ALL;
  }

  if (!Array.isArray(routes))
    routes = [ routes ];

  for (var i = 0, len = routes.length, fullPath, regex, keys; i < len; ++i) {
    if (util.isRegExp(routes[i])) {
      keys = null;
      regex = routes[i];
    } else {
      keys = [];
      if (routes === ROUTES_MATCH_ALL) {
        fullPath = this.path;
        regex = pathRegex(fullPath, keys, { end: false });
      } else {
        fullPath = urljoin(this.path, routes[i]);
        regex = pathRegex(fullPath, keys);
      }
    }

    for (var h = handlersStart; h < handlersEnd; ++h) {
      var handlerfn = arguments[h];
      if (typeof handlerfn !== 'function' && !(handlerfn instanceof Router))
        continue;
      else if (handlerfn instanceof Router) {
        if (keys === null)
          throw new Error('You must specify a string path when mounting a Router');
        else if (handlerfn._mounted)
          throw new Error('Cannot mount a Router in multiple places');
        handlerfn.path = fullPath;
        handlerfn._mounted = true;
        handlerfn = handlerfn.handler;
      }

      this._stack.push([
        regex,
        keys,
        (method ? { method: method, handler: handlerfn } : handlerfn)
      ]);
    }
  }

  return this;
};

Router.prototype.all = Router.prototype.use;

METHODS.forEach(function(method) {
  Router.prototype[method] = function methodRoute(route, handler) {
    switch (arguments.length) {
      case 1:
      case 2:
        return this.use(route, handler, method);

      case 3:
        return this.use(route, handler, arguments[2], method);

      case 4:
        return this.use(route, handler, arguments[2], arguments[3], method);

      case 5:
        return this.use(route,
                        handler,
                        arguments[2],
                        arguments[3],
                        arguments[4],
                        method);

      default:
        var args = new Array(arguments.length + 1);
        for (var i = 0, len = args.length; i < len; ++i)
          args[i] = arguments[i];
        args[i] = method;
        return this.use.apply(this, args);
    }
  };
});

Router.prototype.param = function(name, cb) {
  if (typeof name !== 'string')
    throw new Error('Param name is required');
  if (typeof cb === 'function')
    this._paramFuncs[name] = cb;
};

Router.prototype.route = function(path, opts) {
  var router = new Router(opts);
  this.use(path, router);
  return router;
};

Router.prototype.compress = function() {
  // Call this to compress the current middleware stack. Specifically it
  // combines route handlers for the same route paths to avoid having to call
  // the same regular expressions multiple times.

  // This should only be called before you start serving requests because it
  // modifies the middleware stack and that could mess things up if a request
  // is currently in progress.

  if (this._optimized)
    return;

  var general_path = pathRegex(this.path, [], { end: false });

  var stack = this._stack,
      newStack = [],
      isGeneral = false,
      len = stack.length,
      i,
      layer;

  // first pass, collecting unique non-general route paths
  for (i = 0; i < len; ++i) {
    isGeneral = (regexpsEqual(stack[i][0], general_path)
                 && typeof stack[i][2] === 'function');
    if (!isGeneral) {
      if (!getNewPath(stack[i][0]))
        newStack.push(stack[i]);
    }
  }

  if (newStack.length) {
    // second pass, copying general route handlers to non-general routes
    for (i = 0; i < len; ++i) {
      isGeneral = (regexpsEqual(stack[i][0], general_path)
                   && typeof stack[i][2] === 'function');
      if (isGeneral) {
        // append to all non-general routes
        var handler = stack[i][2];
        for (var j = 0, newlen = newStack.length; j < newlen; ++j) {
          if (newStack[j][2] instanceof Array)
            newStack[j][2].push(handler);
          else
            newStack[j][2] = [ newStack[j][2], handler ];
        }
      } else {
        // we have a non-general route to append
        layer = getNewPath(stack[i][0]);
        if (layer[2] === stack[i][2]) {
          // this was the original route we captured in the first pass, so skip
          // it
          continue;
        }
        if (layer[2] instanceof Array)
          layer[2].push(stack[i][2]);
        else
          layer[2] = [ layer[2], stack[i][2] ];
      }
    }
  } else if (len) {
    // the stack consists only of general middleware, so just keep combine
    // entire stack into one layer
    newStack.push(layer = stack[0]);
    for (i = 1; i < len; ++i) {
      if (layer[2] instanceof Array)
        layer[2].push(stack[i][2]);
      else
        layer[2] = [ layer[2], stack[i][2] ];
    }
  }

  this._stack = newStack;

  this._optimized = true;

  function getNewPath(path) {
    for (var j = 0, newlen = newStack.length; j < newlen; ++j)
      if (regexpsEqual(path, newStack[j][0]))
        return newStack[j];
  }
};

module.exports = Router;

function decodeParam(val) {
  if (typeof val !== 'string')
    return val;

  try {
    return decodeURIComponent(val);
  } catch (e) {
    return false;
  }
}

function makeParams(m, keys) {
  if (!keys)
    return (m && m.length > 1 && m.slice(1, m.length));
  else if (m.length <= 1)
    return;

  var params = {};

  if (m.length > 1)
    params = {};

  for (var i = 1, len = m.length, key, val; i < len; ++i) {
    key = keys[i - 1];
    val = decodeParam(m[i]);
    if (val === false)
      params[key.name] = val;
    else
      params[key.name] = m[i];
  }

  return params;
}

function regexpsEqual(re1, re2) {
  return (re1.source === re2.source
          && re1.global === re2.global
          && re1.ignoreCase === re2.ignoreCase
          && re1.multiline === re2.multiline);
}
<|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('anEkloreQuestion', this.params._id),
			subscriptions.subscribe('aQuestionsGroupForAnEkloreQuestion', this.params._id),
			subscriptions.subscribe('allQuestionsGroups')
		];
	},
	data() {
		return EkloreQuestions.findOne(this.params._id);
	},
	fastRender: true
});
<commit_msg>Update 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('allWorkshopsLinkableToUniverse')];
	},
	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>'use strict';

const express = require('express');
const morgan = require('morgan');

const path = require('path');
const router = express();

const registry = express();
const gui = express();

global.packageFileName = 'package.ccp';

// Configure some settings
router.set('json spaces', 4);

router.use(require('./response'));
router.use('/registry', registry);
router.use('/', gui);

// Registry routes
registry.use(morgan('combined'));

registry.get('/init', require('./routes/init'));

registry.get('/package/:package', require('./routes/package'));
registry.get('/package/:package/:version', require('./routes/install'));
registry.post('/package/:package/:version', require('./authentication'), require('./parser'), require('./routes/publish'));

registry.get('/search', require('./routes/search'));

registry.post('/user', require('./parser'), require('./routes/createuser'));

// UI routes
gui.set('view engine', 'jade');
gui.use(express.static(path.resolve( __dirname, '..', 'public' )));

gui.get('/', require('./routes/gui/index'));

module.exports = router;<commit_msg>Changed morgan log format<commit_after>'use strict';

const url = require('url');
const path = require('path');

const express = require('express');
const morgan = require('morgan');

const router = express();

const registry = express();
const gui = express();

global.packageFileName = 'package.ccp';

// Configure some settings
router.set('json spaces', 4);

router.use(require('./response'));
router.use('/registry', registry);
router.use('/', gui);

// Registry routes
registry.use(morgan('dev', { 'skip': req => /search$/i.test(url.parse(req.url).pathname) }));

registry.get('/init', require('./routes/init'));

registry.get('/package/:package', require('./routes/package'));
registry.get('/package/:package/:version', require('./routes/install'));
registry.post('/package/:package/:version', require('./authentication'), require('./parser'), require('./routes/publish'));

registry.get('/search', require('./routes/search'));

registry.post('/user', require('./parser'), require('./routes/createuser'));

// UI routes
gui.set('view engine', 'jade');
gui.use(express.static(path.resolve( __dirname, '..', 'public' )));

gui.get('/', require('./routes/gui/index'));

module.exports = router;<|endoftext|>