<commit_before>/*
 * Route controller.
 */

/*
 * Module dependencies.
 */
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var express = require('express');
var async = require('async');

/**
 * Main route controller class.
 *
 * @param {Application} application Application.
 * @param {Object} settings Application settings object.
 * @class RouteController
 */
var RouteController = module.exports = function(application, settings) {
  this.application = application;
  this.settings = settings;

  var self = this;
  var app = this.application.application;

  app.all(self.settings.path, function(request, response) {
    self.handle(request, response);
  });
};

/**
 * Handle a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object
 */
RouteController.prototype.handle = function(request, response) {
  var self = this;
  var settings = this.settings;

  this.access(request, response, function(err, allow) {
    if (allow) {
      // A route can have either a content or callback property.
      if (settings.content) {
        self.respond(request, response, settings.content);
      }
      else if (settings.callback) {
        settings.callback(request, response, function(err, content, code) {
          if (content) {
            self.respond(request, response, content, code);
          }
          else {
            // If there's no content, return 404 error.
            self.notFound(request, response);
          }
        });
      }
    }
    else {
      // Access denied.
      self.forbidden(request, response);
    }
  });
};

/**
 * Access check.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Function} callaback Function called with the access check results.
 */
RouteController.prototype.access = function(request, response, callback) {
  var self = this;
  var settings = this.settings;

  // If this is an object, do access check and other mandatory stuff.
  if (settings.access) {
    if (typeof settings.access === 'boolean') {
      // Access check is a string/permission key.
      return callback(null, settings.access);
    }
    else if (typeof settings.access === 'function') {
      // Access check is a callback.
      return settings.access(request, response, callback);
    }
  }

  // Default to false. Deny access.
  return callback(null, false);
};

/**
 * Respond to a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Object|String} content Content to send.
 * @param {Number} [code] HTTP status code.
 */
RouteController.prototype.respond = function(request, response, content, code) {
  // Default to 200 (success).
  var code = code || 200;

  var payload = {
    status: {
      code: code
    }
  };

  var alerts = request.flash();
  if (Object.keys(alerts).length > 0) {
    payload.alerts = alerts;
  }

  if (content) {
    payload.data = content;
  }

  response.send(code, payload);
};

/**
 * Respond to a request with a "page not found" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.prototype.notFound = function(request, response) {
  this.respond(request, response, {
    title: 'Page not found',
    description: "The page you're looking for wasn't found."
  }, 404);
};

/**
 * Respond to a request with a "forbidden" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.<commit_msg>Improving error handling on the route controller.<commit_after>/*
 * Route controller.
 */

/*
 * Module dependencies.
 */
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var express = require('express');
var async = require('async');

/**
 * Main route controller class.
 *
 * @param {Application} application Application.
 * @param {Object} settings Application settings object.
 * @class RouteController
 */
var RouteController = module.exports = function(application, settings) {
  this.application = application;
  this.settings = settings;

  var self = this;
  var app = this.application.application;

  app.all(self.settings.path, function(request, response) {
    self.handle(request, response);
  });
};

/**
 * Handle a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object
 */
RouteController.prototype.handle = function(request, response) {
  var self = this;
  var settings = this.settings;

  this.access(request, response, function(err, allow) {
    if (err) {
      self.error(request, response, err);
    }

    if (allow) {
      // A route can have either a content or callback property.
      if (settings.content) {
        self.respond(request, response, settings.content);
      }
      else if (settings.callback) {
        settings.callback(request, response, function(err, content, code) {
          if (err) {
            self.error(request, response, err);
          }

          if (content) {
            self.respond(request, response, content, code);
          }
          else {
            // If there's no content, return 404 error.
            self.notFound(request, response);
          }
        });
      }
    }
    else {
      // Access denied.
      self.forbidden(request, response);
    }
  });
};

/**
 * Access check.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Function} callaback Function called with the access check results.
 */
RouteController.prototype.access = function(request, response, callback) {
  var self = this;
  var settings = this.settings;

  // If this is an object, do access check and other mandatory stuff.
  if (settings.access) {
    if (typeof settings.access === 'boolean') {
      // Access check is a string/permission key.
      return callback(null, settings.access);
    }
    else if (typeof settings.access === 'function') {
      // Access check is a callback.
      return settings.access(request, response, callback);
    }
  }

  // Default to false. Deny access.
  return callback(null, false);
};

/**
 * Respond to a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Object|String} content Content to send.
 * @param {Number} [code] HTTP status code.
 */
RouteController.prototype.respond = function(request, response, content, code) {
  // Default to 200 (success).
  var code = code || 200;

  var payload = {
    status: {
      code: code
    }
  };

  var alerts = request.flash();
  if (Object.keys(alerts).length > 0) {
    payload.alerts = alerts;
  }

  if (content) {
    payload.data = content;
  }

  response.send(code, payload);
};

/**
 * Respond to a request with a "server error".
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.prototype.error = function(request, response, error) {
  this.respond(request, response, {
    title: 'Server error',
    description: "The server couldn't process the request.",
    error: error.toString()
  }, 500);
};

/**
 * Respond to a request with a "page not found" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.prototype.notFound = function(request, response) {
  this.respond(request, response, {
    title: 'Page not found',
    description: "The page you're looking for wasn't found."
  }, 404);
};

/**
 * Respond to a request with a "forbidden" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
{'fraction_non_alphanumeric': 0.12790245167985473, 'fraction_numerical': 0.003761836814113374, 'mean_word_length': 2.9906832298136647, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2274529', 'n_tokens_mistral': 2196, 'n_tokens_neox': 2135, 'n_words': 692}