<commit_before>/*jslint white: true, nomen: true, indent: 2, sub: true */
/*global require, console, setTimeout */

/**
 * @author brian@bevey.org
 * @fileoverview Interface for various hardware controllers.
 * @requires http, url, path, fs
 */

var http        = require('http'),
    url         = require('url'),
    path        = require('path'),
    fs          = require('fs'),
    nopt        = require('nopt'),
    knownOpts   = { 'config' : path },
    shortHands  = { 'c' : ['--config'] },
    parsed      = nopt(knownOpts, shortHands, process.argv, 2),
    controllers = {}, settings;

if(parsed.config) {
  settings = require(parsed.config);
} else {
  settings = require('./config/config');
}

// Only load controllers if they're configured.
(function() {
  'use strict';

  var deviceName;

  for(deviceName in settings.config) {
    if((typeof settings.config[deviceName] === 'object') && (settings.config[deviceName]['disabled'] !== true)) {
      settings.config[deviceName]['deviceID'] = deviceName;

      controllers[deviceName] = require('./controllers/' + settings.config[deviceName]['typeClass'] + 'Controller');

      console.log('Loaded ' + settings.config[deviceName]['typeClass'] + ' controller for ' + settings.config[deviceName]['title']);

      if(controllers[deviceName]['init'] !== undefined) {
        controllers[deviceName]['init']();
      }
    }
  }
}());

http.createServer(function(request, response) {
  'use strict';

  request.on('end', function () {
    var runCommand,
        directory,
        deviceController,
        _get      = url.parse(request.url, true).query,
        device    = _get.device || settings.config[settings.config.default]['deviceID'],
        filename  = path.basename(request.url),
        extension = path.extname(filename),
        exists    = fs.exists || path.exists,
        mimeTypes = {'.html' : 'text/html',
                     '.css'  : 'text/css',
                     '.js'   : 'application/javascript',
                     '.ico'  : 'image/x-icon',
                     '.eot'  : 'application/vnd.ms-fontobject',
                     '.svg'  : 'image/svg+xml',
                     '.ttf'  : 'application/x-font-ttf',
                     '.woff' : 'application/x-font-woff'};

    switch(extension) {
      case '.css' :
        directory = 'css';
        break;
      case '.js' :
        directory = 'js';
        break;
      case '.ico' :
      case '.eot' :
      case '.svg' :
      case '.ttf' :
      case '.woff' :
        directory = 'font';
        break;
    }

    /* Serve static assets */
    if(directory) {
      exists(directory + '/' + filename, function(exists) {
        if(exists) {
          fs.readFile(directory + '/' + filename, 'utf-8', function(error, contents) {
            if(!error) {
              response.writeHead(200, {'Content-Type': mimeTypes[extension], 'Content-Length': contents.length});
              response.end(contents);
            }
          });
        }
      });
    }

    /* Or the remote controller */
    else {
      runCommand = function(config) {
        var value          = 'bad',
            deviceSettings = settings.config[device] || {},
            command        = config.command          || '',
            macro          = config.macro            || '',
            text           = config.text             || '',
            launch         = config.launch           || '',
            endResponse    = config.endResponse      || false,
            singleCommand,
            runMacro;

        deviceSettings.serverIp  = settings.config.serverIp;
        deviceSettings.serverMac = settings.config.serverMac;
        deviceSettings.command   = '';
        deviceSettings.macro     = '';
        deviceSettings.text      = '';
        deviceSettings.list      = '';
        deviceSettings.launch    = '';

        singleCommand = function(command) {
          if(deviceController.keymap.indexOf(command) >= 0) {
            deviceSettings.cbConnect = function () {
              deviceSettings.status = 'connected';

              if(endResponse) {
                response.end('{"command":"' + command + '","device":"' + deviceSettings.title + '","cmdStatus":"ok"}');
              }
            };

            deviceSettings.cbError = function (errorMsg) {
              if(errorMsg === 'Device is off or unreachable') {
                deviceSettings.status = 'disconnected';
              }

              if(endResponse) {
                response.end('{"command":"' + command + '","device":"' + deviceSettings.title + '","cmdStatus":"' + errorMsg + '"}');
              }
            };

            console.log('Device: ' + deviceSettings.title + ', Good Command: ' + command);
            deviceSettings.command = command;

            value = deviceController.send(deviceSettings);
          }

          else if(command === 'sleep') {
            console.log('Sleep command sent');

            value = 'sleep';
          }

          else if(command) {
            console.log('Device: ' + deviceSettings.title + ', Bad Command: ' + command);

            value = 'invalid';
          }

          return value;
        };

        runMacro = function(i, macro) {
          var tempCommand = macro[i];

          if(tempCommand) {
            value = value + singleCommand(tempCommand);

            setTimeout(function() {
              runMacro(i + 1, macro);
            }, 1000);
          }
        };

        if(text) {
          deviceSettings.cbConnect = function () {
            settings.status = 'connected';
            if(endResponse) {
              response.end('{"text":"' + text + '","device":"' + deviceSettings.title + '", "cmdStatus":"ok"}');
            }
          };

          deviceSettings.cbError = function (errorMsg) {
            if(errorMsg === 'Device is off or unreachable') {
              deviceSettings.status = 'disconnected';
            }

            if(endResponse) {
              response.end('{"text":"' + text + '","device":"' + deviceSettings.title + '","cmdStatus":"' + errorMsg + '"}');
            }
          };

          console.log('Text inputted: ' + text);
          deviceSettings.text = text;

          value = deviceController.send(deviceSettings);
        }

        if(launch) {
          deviceSettings.cbConnect = function () {
            settings.status = 'connected';
            if(endResponse) {
              response.end('{"launch":"' + launch + '","device":"' + deviceSettings.title + '","cmdStatus":"ok"}');
            }
          };

          deviceSettings.cbError = function (errorMsg) {
            if(errorMsg === 'Device is off or unreachable') {
              deviceSettings.status = 'disconnected';
            }

            if(endResponse) {
              response.end('{"launch":"' + launch + '","device":"' + deviceSettings.title + '","cmdStatus":"' + errorMsg + '"}');
            }
          };

          console.log('Device: ' + deviceSettings.title + ', Launch: ' + launch);
          deviceSettings.launch = launch;

          value = deviceController.send(deviceSettings);
        }

        if(macro) {
          macro = macro.split(',');

          runMacro(0, macro);

          value = '{"macro":' + value + '}';
        }

        if(command) {
          value = singleCommand(command);
        }

        return value;
      };

      if(typeof controllers[device] === 'object') {
        deviceController = controllers[device][settings.config[device]['typeClass'] + 'Controller'];
      }

      // If XHR, return JSON
      if(request.headers.ajax) {
        response.writeHead(200, { 'Content-Type': mimeTypes['.js'] });

        runCommand({ command: _get.command, macro: _get.macro, text: _get.text, list: _get.list, launch: _get.launch, endResponse: true });
      }

      // Otherwise, show the markup
      else {
        fs.readFile(path.join(__dirname + '/templates/markup.html'), 'utf-8', function(error, markup) {
          response.writeHead(200, {'Content-Type': mimeTypes['.html']});

          runCommand({ command: _get.command, macro: _get.macro, text: _get.text, list: _get.list, launch: _get.launch, endResponse: false });

          // I'm not using mustache, but I can pretend.
          markup = markup.replace('{{DEVICE}}', device);

          markup = markup.replace('{{THEME}}', settings.config.theme || 'standard');

          // Load up content templates for each device type.
          (function() {
            var deviceName,
                tempDevice,
                staticContent,
                staticDevices = [],
                onloadDevices = [],
                i = 0,
                j = 0;

            staticContent = function (template, data, navTemplate, navData, staticDevices, index, dataResponse) {
              var config;

              // Continue loading static templates and appropriate nav
              // elements.
              if(index >= 0) {
                config  = staticDevices[index]['config'];
                navData = navData + navTemplate.split('{{DEVICE_ID}}').join(config.deviceID);
                navData = navData.split('{{DEVICE_TITLE}}').join(config.title);

                fs.readFile(path.join(__dirname + '/templates/' + config.typeClass + '.tpl'), 'utf-8', function(error, deviceData) {
                  deviceData = deviceData.split('{{DEVICE_ID}}').join(config.deviceID);

                  staticContent(template, data + deviceData, navTemplate, navData, staticDevices, index - 1, dataResponse);
                });
              }

              else {
                markup = markup.replace('{{NAVIGATION}}', navData);
                markup = markup.replace('{{DEVICE_INTERFACES}}', data);

                // Once we load each static template, we can see if a device
                // has anything we need to load onload
                if(j) {
                  j -= 1;
                  onloadDevices[j]['controller']['onload'](markup, onloadDevices, j, response);
                }

                else {
                  response.end(markup);
                }
              }
            };

            for(deviceName in controllers) {
              tempDevice = controllers[deviceName][settings.config[deviceName]['typeClass'] + 'Controller'];

              if(typeof tempDevice === 'object') {
                staticDevices[i] = { 'controller': tempDevice, 'config': settings.config[deviceName] };
                i += 1;

                if(tempDevice.onload !== undefined) {
                  onloadDevices[j] = { 'controller': tempDevice, 'config': settings.config[deviceName] };
                  j += 1;
                }
              }
            }

            i -= 1;

            fs.readFile(path.join(__dirname + '/templates/fragments/navigation.tpl'), 'utf-8', function(error, navTemplate) {
              staticContent(markup, '', navTemplate, '', staticDevices.reverse(), i, response);
            });
          }());
        });
      }
    }
  });

  request.resume();
}).listen(settings.config.serverPort, '0.0.0.0');
<commit_msg>Asset path needs to be local to app dirname<commit_after>/*jslint white: true, nomen: true, indent: 2, sub: true */
/*global require, console, setTimeout */

/**
 * @author brian@bevey.org
 * @fileoverview Interface for various hardware controllers.
 * @requires http, url, path, fs
 */

var http        = require('http'),
    url         = require('url'),
    path        = require('path'),
    fs          = require('fs'),
    nopt        = require('nopt'),
    knownOpts   = { 'config' : path },
    shortHands  = { 'c' : ['--config'] },
    parsed      = nopt(knownOpts, shortHands, process.argv, 2),
    controllers = {}, settings;

if(parsed.config) {
  settings = require(parsed.config);
} else {
  settings = require('./config/config');
}

// Only load controllers if they're configured.
(function() {
  'use strict';

  var deviceName;

  for(deviceName in settings.config) {
    if((typeof settings.config[deviceName] === 'object') && (settings.config[deviceName]['disabled'] !== true)) {
      settings.config[deviceName]['deviceID'] = deviceName;

      controllers[deviceName] = require('./controllers/' + settings.config[deviceName]['typeClass'] + 'Controller');

      console.log('Loaded ' + settings.config[deviceName]['typeClass'] + ' controller for ' + settings.config[deviceName]['title']);

      if(controllers[deviceName]['init'] !== undefined) {
        controllers[deviceName]['init']();
      }
    }
  }
}());

http.createServer(function(request, response) {
  'use strict';

  request.on('end', function () {
    var runCommand,
        assetPath,
        directory,
        deviceController,
        _get      = url.parse(request.url, true).query,
        device    = _get.device || settings.config[settings.config.default]['deviceID'],
        filename  = path.basename(request.url),
        extension = path.extname(filename),
        exists    = fs.exists || path.exists,
        mimeTypes = {'.html' : 'text/html',
                     '.css'  : 'text/css',
                     '.js'   : 'application/javascript',
                     '.ico'  : 'image/x-icon',
                     '.eot'  : 'application/vnd.ms-fontobject',
                     '.svg'  : 'image/svg+xml',
                     '.ttf'  : 'application/x-font-ttf',
                     '.woff' : 'application/x-font-woff'};

    switch(extension) {
      case '.css' :
        directory = 'css';
        break;
      case '.js' :
        directory = 'js';
        break;
      case '.ico' :
      case '.eot' :
      case '.svg' :
      case '.ttf' :
      case '.woff' :
        directory = 'font';
        break;
    }

    /* Serve static assets */
    if(directory) {
      assetPath = path.join(__dirname + '/' + directory + '/' + filename);

      exists(assetPath, function(exists) {
        if(exists) {
          fs.readFile(assetPath, 'utf-8', function(error, contents) {
            if(!error) {
              response.writeHead(200, {'Content-Type': mimeTypes[extension], 'Content-Length': contents.length});
              response.end(contents);
            }
          });
        }
      });
    }

    /* Or the remote controller */
    else {
      runCommand = function(config) {
        var value          = 'bad',
            deviceSettings = settings.config[device] || {},
            command        = config.command          || '',
            macro          = config.macro            || '',
            text           = config.text             || '',
            launch         = config.launch           || '',
            endResponse    = config.endResponse      || false,
            singleCommand,
            runMacro;

        deviceSettings.serverIp  = settings.config.serverIp;
        deviceSettings.serverMac = settings.config.serverMac;
        deviceSettings.command   = '';
        deviceSettings.macro     = '';
        deviceSettings.text      = '';
        deviceSettings.list      = '';
        deviceSettings.launch    = '';

        singleCommand = function(command) {
          if(deviceController.keymap.indexOf(command) >= 0) {
            deviceSettings.cbConnect = function () {
              deviceSettings.status = 'connected';

              if(endResponse) {
                response.end('{"command":"' + command + '","device":"' + deviceSettings.title + '","cmdStatus":"ok"}');
              }
            };

            deviceSettings.cbError = function (errorMsg) {
              if(errorMsg === 'Device is off or unreachable') {
                deviceSettings.status = 'disconnected';
              }

              if(endResponse) {
                response.end('{"command":"' + command + '","device":"' + deviceSettings.title + '","cmdStatus":"' + errorMsg + '"}');
              }
            };

            console.log('Device: ' + deviceSettings.title + ', Good Command: ' + command);
            deviceSettings.command = command;

            value = deviceController.send(deviceSettings);
          }

          else if(command === 'sleep') {
            console.log('Sleep command sent');

            value = 'sleep';
          }

          else if(command) {
            console.log('Device: ' + deviceSettings.title + ', Bad Command: ' + command);

            value = 'invalid';
          }

          return value;
        };

        runMacro = function(i, macro) {
          var tempCommand = macro[i];

          if(tempCommand) {
            value = value + singleCommand(tempCommand);

            setTimeout(function() {
              runMacro(i + 1, macro);
            }, 1000);
          }
        };

        if(text) {
          deviceSettings.cbConnect = function () {
            settings.status = 'connected';
            if(endResponse) {
              response.end('{"text":"' + text + '","device":"' + deviceSettings.title + '", "cmdStatus":"ok"}');
            }
          };

          deviceSettings.cbError = function (errorMsg) {
            if(errorMsg === 'Device is off or unreachable') {
              deviceSettings.status = 'disconnected';
            }

            if(endResponse) {
              response.end('{"text":"' + text + '","device":"' + deviceSettings.title + '","cmdStatus":"' + errorMsg + '"}');
            }
          };

          console.log('Text inputted: ' + text);
          deviceSettings.text = text;

          value = deviceController.send(deviceSettings);
        }

        if(launch) {
          deviceSettings.cbConnect = function () {
            settings.status = 'connected';
            if(endResponse) {
              response.end('{"launch":"' + launch + '","device":"' + deviceSettings.title + '","cmdStatus":"ok"}');
            }
          };

          deviceSettings.cbError = function (errorMsg) {
            if(errorMsg === 'Device is off or unreachable') {
              deviceSettings.status = 'disconnected';
            }

            if(endResponse) {
              response.end('{"launch":"' + launch + '","device":"' + deviceSettings.title + '","cmdStatus":"' + errorMsg + '"}');
            }
          };

          console.log('Device: ' + deviceSettings.title + ', Launch: ' + launch);
          deviceSettings.launch = launch;

          value = deviceController.send(deviceSettings);
        }

        if(macro) {
          macro = macro.split(',');

          runMacro(0, macro);

          value = '{"macro":' + value + '}';
        }

        if(command) {
          value = singleCommand(command);
        }

        return value;
      };

      if(typeof controllers[device] === 'object') {
        deviceController = controllers[device][settings.config[device]['typeClass'] + 'Controller'];
      }

      // If XHR, return JSON
      if(request.headers.ajax) {
        response.writeHead(200, { 'Content-Type': mimeTypes['.js'] });

        runCommand({ command: _get.command, macro: _get.macro, text: _get.text, list: _get.list, launch: _get.launch, endResponse: true });
      }

      // Otherwise, show the markup
      else {
        fs.readFile(path.join(__dirname + '/templates/markup.html'), 'utf-8', function(error, markup) {
          response.writeHead(200, {'Content-Type': mimeTypes['.html']});

          runCommand({ command: _get.command, macro: _get.macro, text: _get.text, list: _get.list, launch: _get.launch, endResponse: false });

          // I'm not using mustache, but I can pretend.
          markup = markup.replace('{{DEVICE}}', device);

          markup = markup.replace('{{THEME}}', settings.config.theme || 'standard');

          // Load up content templates for each device type.
          (function() {
            var deviceName,
                tempDevice,
                staticContent,
                staticDevices = [],
                onloadDevices = [],
                i = 0,
                j = 0;

            staticContent = function (template, data, navTemplate, navData, staticDevices, index, dataResponse) {
              var config;

              // Continue loading static templates and appropriate nav
              // elements.
              if(index >= 0) {
                config  = staticDevices[index]['config'];
                navData = navData + navTemplate.split('{{DEVICE_ID}}').join(config.deviceID);
                navData = navData.split('{{DEVICE_TITLE}}').join(config.title);

                fs.readFile(path.join(__dirname + '/templates/' + config.typeClass + '.tpl'), 'utf-8', function(error, deviceData) {
                  deviceData = deviceData.split('{{DEVICE_ID}}').join(config.deviceID);

                  staticContent(template, data + deviceData, navTemplate, navData, staticDevices, index - 1, dataResponse);
                });
              }

              else {
                markup = markup.replace('{{NAVIGATION}}', navData);
                markup = markup.replace('{{DEVICE_INTERFACES}}', data);

                // Once we load each static template, we can see if a device
                // has anything we need to load onload
                if(j) {
                  j -= 1;
                  onloadDevices[j]['controller']['onload'](markup, onloadDevices, j, response);
                }

                else {
                  response.end(markup);
                }
              }
            };

            for(deviceName in controllers) {
              tempDevice = controllers[deviceName][settings.config[deviceName]['typeClass'] + 'Controller'];

              if(typeof tempDevice === 'object') {
                staticDevices[i] = { 'controller': tempDevice, 'config': settings.config[deviceName] };
                i += 1;

                if(tempDevice.onload !== undefined) {
                  onloadDevices[j] = { 'controller': tempDevice, 'config': settings.config[deviceName] };
                  j += 1;
                }
              }
            }

            i -= 1;

            fs.readFile(path.join(__dirname + '/templates/fragments/navigation.tpl'), 'utf-8', function(error, navTemplate) {
              staticContent(markup, '', navTemplate, '', staticDevices.reverse(), i, response);
            });
          }());
        });
      }
    }
  });

  request.resume();
}).listen(settings.config.serverPort, '0.0.0.0');
<|endoftext|>


<commit_before>/* global require, module, process, console, __dirname */
/* jshint -W097 */
'use strict';

// BASE SETUP
// =============================================================================
var
  fs         = require('fs'),
  express    = require('express'),
  bodyParser = require('body-parser'),
  mongoose   = require('mongoose'),

  rootDir    = __dirname + '/../../',
  publicDir  = rootDir + 'dist/',
  routesDir  = __dirname + '/routes/',
  port       = process.env.PORT || 5000,
  app        = express();

// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// configure app to serve static files from the dist directory
app.use(express.static(publicDir));

// root
app.get('/', function(req, res) {
    res.sendfile(publicDir + 'index.html');
});

// MONGO CONF.
// =============================================================================
var mongoConfigParser = require('./lib/mongoConfigParser');

var mongoConn = new mongoConfigParser()
  .setEnvDir( rootDir + 'db/mongo/env' )
  .getConnectionString();

// connect
mongoose.connect(mongoConn)

// API ROUTES
// =============================================================================

var router = express.Router();

// middleware to use for all requests
router.use(function(req, res, next) {
  next(); // make sure we go to the next routes and don't stop here
});

// test route to make sure everything is working (accessed at GET http://localhost:PORT/api)
router.get('/', function(req, res) {
  res.json({ message: 'hooray! welcome to our api!' });
});

// load the routes
fs.readdirSync(routesDir).forEach(function(file) {
  var route = routesDir + file.substr(0, file.indexOf('.'));
  console.log('Adding route:' + route);
  require(route)(router);
});

// REGISTER THE ROUTES
// all of our routes will be prefixed with /api
app.use('/api', router);

// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Server running on port ' + port);
<commit_msg>Add missing semicolon<commit_after>/* global require, module, process, console, __dirname */
/* jshint -W097 */
'use strict';

// BASE SETUP
// =============================================================================
var
  fs         = require('fs'),
  express    = require('express'),
  bodyParser = require('body-parser'),
  mongoose   = require('mongoose'),

  rootDir    = __dirname + '/../../',
  publicDir  = rootDir + 'dist/',
  routesDir  = __dirname + '/routes/',
  port       = process.env.PORT || 5000,
  app        = express();

// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// configure app to serve static files from the dist directory
app.use(express.static(publicDir));

// root
app.get('/', function(req, res) {
    res.sendfile(publicDir + 'index.html');
});

// MONGO CONF.
// =============================================================================
var mongoConfigParser = require('./lib/mongoConfigParser');

var mongoConn = new mongoConfigParser()
  .setEnvDir( rootDir + 'db/mongo/env' )
  .getConnectionString();

// connect
mongoose.connect(mongoConn);

// API ROUTES
// =============================================================================

var router = express.Router();

// middleware to use for all requests
router.use(function(req, res, next) {
  next(); // make sure we go to the next routes and don't stop here
});

// test route to make sure everything is working (accessed at GET http://localhost:PORT/api)
router.get('/', function(req, res) {
  res.json({ message: 'hooray! welcome to our api!' });
});

// load the routes
fs.readdirSync(routesDir).forEach(function(file) {
  var route = routesDir + file.substr(0, file.indexOf('.'));
  console.log('Adding route:' + route);
  require(route)(router);
});

// REGISTER THE ROUTES
// all of our routes will be prefixed with /api
app.use('/api', router);

// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Server running on port ' + port);
<|endoftext|>


<commit_before>const Discord = require('discord.js');
const client = new Discord.Client();
const token = process.env.DISCORD_TOKEN;

const prefix = '^';

client.on('ready', () => {
	console.log('I am ready!');
});

client.on('message', message => {
	if (message.content.substring(0, prefix.length) == prefix) {
		handleCommand(message);
	}
});

function handleCommand(message) {
	var cmd = message.content.substring(prefix.length).split(' ', 1);
	console.log('cmd: ' + cmd);
	switch (cmd[0]) {
		case 'ping':
			cmdPing(message, cmd[1]);
			break;

		default:
			message.reply('Unrecognized command.');
			break;
	}
}

function cmdPing(message, arguments) {
	const embed = new Discord.RichEmbed()
			.setColor(Math.floor(Math.random() * 16777216))
			.setDescription('🏓 Pong!');
	message.channel.send({embed})
			.then(msg => msg.edit(embed.setDescription(embed.description + ' ' + (message.createdTimestamp - msg.createdTimestamp) + 'ms')))
			.catch(console.error);
}

client.login(token);<commit_msg>Debugging.<commit_after>const Discord = require('discord.js');
const client = new Discord.Client();
const token = process.env.DISCORD_TOKEN;

const prefix = '^';

client.on('ready', () => {
	console.log('I am ready!');
});

client.on('message', message => {
	if (message.content.substring(0, prefix.length) == prefix) {
		handleCommand(message);
	}
});

var handleCommand = message => {
	var cmd = message.content.substring(prefix.length).split(' ', 1);
	switch (cmd[0]) {
		case 'ping':
			cmdPing(message, cmd[1]);
			break;

		default:
			message.reply('Unrecognized command.');
			break;
	}
}

var cmdPing = (message, arguments) => {
	const embed = new Discord.RichEmbed()
			.setColor(Math.floor(Math.random() * 16777216))
			.setDescription('🏓 Pong!');
	message.channel.send({embed})
			.then(msg => {
				embed.setDescription(embed.description + ' ' + (message.createdTimestamp - msg.createdTimestamp) + 'ms');
				msg.edit({embed});
			}).catch(console.error);
}

client.login(token);<|endoftext|>


<commit_before>/**
Bootlint HTTP server API
Run it via: npm run start
This is pretty niche. Most users should probably use the CLI or bookmarklet instead.
*/

/*eslint-env node */

'use strict';

var bootlint = require('./src/bootlint');
var _extend = require('util')._extend;
var express = require('express');
var logger = require('morgan');
var bodyParser = require('body-parser');

var HTML_MIME_TYPES = [
    'text/html',
    'application/xhtml+xml'
];

function shallowClone(obj) {
    return _extend({}, obj);
}

function disabledIdsFor(req) {
    var rawIds = req.query.disable;
    if (!rawIds) {
        return [];
    }
    return rawIds.split(',');
}

function lintsFor(html, disabledIds) {
    var lints = [];
    var reporter = function (lint) {
        var output = false;
        if (lint.elements && lint.elements.length) {
            var elements = lint.elements;
            lint.elements = undefined;
            elements.each(function (_, element) {
                if (element.startLocation) {
                    var locatedLint = shallowClone(lint);
                    locatedLint.location = element.startLocation;
                    lints.push(locatedLint);
                    output = true;
                }
            });
        }
        if (!output) {
            lint.elements = undefined;
            lints.push(lint);
        }
    };
    bootlint.lintHtml(html, reporter, disabledIds);
    return lints;
}

/*eslint-disable new-cap */
var routes = express.Router();
/*eslint-enable new-cap */

routes.get('/', function (req, res) {
    res.status(200).json({status: 200, message: 'Bootlint is online!'});
});

routes.post('/', function (req, res) {
    var isHtml = HTML_MIME_TYPES.some(function (type) {
        return req.is(type);
    });
    if (!isHtml) {
        res.status(415).json({status: 415, message: 'Unsupported Media Type', details: 'Content-Type was not an HTML MIME type'});
        return;
    }

    res.format({
        'application/json': function () {
            var disabledIds = disabledIdsFor(req);
            var html = req.body;
            // console.log("HTML: ", html);
            var lints = lintsFor(html, disabledIds);
            res.status(200).json(lints);
        },
        'default': function () {
            res.status(406).json({status: 406, message: 'Not Acceptable', details: '"Accept" header must allow MIME type application/json'});
        }
    });
});

var app = express();

app.use(logger('dev'));
HTML_MIME_TYPES.forEach(function (type) {
    app.use(bodyParser.text({type: type}));
});

app.use('/', routes);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace

/*eslint-disable no-unused-vars */
app.use(function (err, req, res, next) {
    var isHttpErr = !!err.status;

    if (!isHttpErr) {
        err.status = 500;
    }

    var errJson = {
        status: err.status,
        message: err.message
    };
    if (!isHttpErr) {
        errJson.stack = err.stack;
    }

    res.status(err.status).json(errJson);
});
/*eslint-enable no-unused-vars */

module.exports = app;
<commit_msg>HTTP API: Set max incoming entity size<commit_after>/**
Bootlint HTTP server API
Run it via: npm run start
This is pretty niche. Most users should probably use the CLI or bookmarklet instead.
*/

/*eslint-env node */

'use strict';

var bootlint = require('./src/bootlint');
var _extend = require('util')._extend;
var express = require('express');
var logger = require('morgan');
var bodyParser = require('body-parser');

var HTML_MIME_TYPES = [
    'text/html',
    'application/xhtml+xml'
];
// For context, unminified bootstrap.css + bootstrap.js is ~200KiB,
// and JSFiddle inlines the contents of the CSS and JS panes of its editor into the resulting HTML.
var MAX_HTML_SIZE = '1MB';

function shallowClone(obj) {
    return _extend({}, obj);
}

function disabledIdsFor(req) {
    var rawIds = req.query.disable;
    if (!rawIds) {
        return [];
    }
    return rawIds.split(',');
}

function lintsFor(html, disabledIds) {
    var lints = [];
    var reporter = function (lint) {
        var output = false;
        if (lint.elements && lint.elements.length) {
            var elements = lint.elements;
            lint.elements = undefined;
            elements.each(function (_, element) {
                if (element.startLocation) {
                    var locatedLint = shallowClone(lint);
                    locatedLint.location = element.startLocation;
                    lints.push(locatedLint);
                    output = true;
                }
            });
        }
        if (!output) {
            lint.elements = undefined;
            lints.push(lint);
        }
    };
    bootlint.lintHtml(html, reporter, disabledIds);
    return lints;
}

/*eslint-disable new-cap */
var routes = express.Router();
/*eslint-enable new-cap */

routes.get('/', function (req, res) {
    res.status(200).json({status: 200, message: 'Bootlint is online!'});
});

routes.post('/', function (req, res) {
    var isHtml = HTML_MIME_TYPES.some(function (type) {
        return req.is(type);
    });
    if (!isHtml) {
        res.status(415).json({status: 415, message: 'Unsupported Media Type', details: 'Content-Type was not an HTML MIME type'});
        return;
    }

    res.format({
        'application/json': function () {
            var disabledIds = disabledIdsFor(req);
            var html = req.body;
            // console.log("HTML: ", html);
            var lints = lintsFor(html, disabledIds);
            res.status(200).json(lints);
        },
        'default': function () {
            res.status(406).json({status: 406, message: 'Not Acceptable', details: '"Accept" header must allow MIME type application/json'});
        }
    });
});

var app = express();

app.use(logger('dev'));
HTML_MIME_TYPES.forEach(function (type) {
    app.use(bodyParser.text({type: type, limit: MAX_HTML_SIZE}));
});

app.use('/', routes);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace

/*eslint-disable no-unused-vars */
app.use(function (err, req, res, next) {
    var isHttpErr = !!err.status;

    if (!isHttpErr) {
        err.status = 500;
    }

    var errJson = {
        status: err.status,
        message: err.message
    };
    if (!isHttpErr) {
        errJson.stack = err.stack;
    }

    res.status(err.status).json(errJson);
});
/*eslint-enable no-unused-vars */

module.exports = app;
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var insult = require('./routes/insult');

var app = express();
// uncomment after placing your favicon in /public
app.use(favicon(__dirname + '/public/favicon.ico'));

// Pull Riot API key from enviromental variables.
apiKey = process.env.RIOTKEY;

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/insult', insult);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;
<commit_msg>Favicon testing<commit_after>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var insult = require('./routes/insult');

var app = express();

// uncomment after placing your favicon in /public
app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(favicon(path.join(__dirname,'public','favicon.ico')));

// Pull Riot API key from enviromental variables.
apiKey = process.env.RIOTKEY;

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/insult', insult);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;
<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs');
var express = require('express');
var helmet = require('helmet');
var url = require('url');

var React = require('react');
var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var match = ReactRouter.match;
var routington = require('routington');

var indexStaticWatcher = require('./lib/build/index-static-watcher').create();
var PORT = process.env.PORT || 8008;
var PRODUCTION = (process.env.NODE_ENV === 'production');
var DIST_DIR = path.join(__dirname, 'dist');
var CODEMOJI_URL = process.env.CODEMOJI_URL || "https://codemoji.mofostaging.net";
var localize = require('mofo-localize');

var WpPageChecker = require('./lib/wp-page-checker');

var habitat = require('habitat');
habitat.load('.env');

var indexStatic;
var router;
var matcher;
var app = express();
var locale = "";
var locales = require('./dist/locales.json')

app.disable('x-powered-by');

var notFoundHTML = [
  '<!doctype html>',
  '',
  '<meta charset="utf-8">',
  '<title>404 - Page not found</title>',
  '',
  '
404 - Page not found
',
  ''
].join('');

var urlToRoutePath = function(loc) {
  // For router-resolution, we don't want hashes...
  var pos = loc.indexOf('#');
  if (pos > -1) { loc = loc.substring(0,pos); }
  // And we don't want query strings, either...
  pos = loc.indexOf('?');
  if (pos > -1) { loc = loc.substring(0,pos); }
  // If this is not the site root, we need to remove the leading slash.
  if (loc !== '/') {
    loc = loc.replace(/^\//, '').replace(/\/$/, '');
  }
  return loc;
};

var startProdApp = function() {
  console.log([
    'Production mode enabled. Note that "npm install" is assumed to',
    'have recently been run with NODE_ENV="production". If this is not',
    'the case, some or all static assets may be out of date.'
  ].join('\n'));
  indexStaticWatcher.build(function(err, newIndexStatic) {
    if (err) {
      throw err;
    }

    console.log('Built server-side bundle.');
    updateIndexStatic(newIndexStatic);
    app.listen(PORT, function() {
      console.log('Listening on port', PORT);
    });
  });
};

var updateIndexStatic = function(newIndexStatic) {
  indexStatic = newIndexStatic;
  router = indexStatic ? React.createElement(Router, {routes: indexStatic.routes}) : null;
};

// make sure the dir we'll be using for static hosting exists.
if (!fs.existsSync(DIST_DIR)) {
  fs.mkdirSync(DIST_DIR);
}

/**
 * Security Headers
 */
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: [
      'www.youtube.com',
      'https://public.etherpad-mozilla.org',
      'https://pontoon.mozilla.org'
    ],
    scriptSrc: [
      '\'self\'',
      '\'unsafe-inline\'',
      '\'unsafe-eval\'',
      'data:',
      'www.google-analytics.com',
      'cdn.optimizely.com',
      'https://www.google.com',
      'https://s.ytimg.com',
      'https://www.mozilla.org',
      'https://pontoon.mozilla.org'
    ],
    fontSrc: [
      '\'self\'',
      'fonts.googleapis.com',
      'fonts.gstatic.com',
      'https://pontoon.mozilla.org'
    ],
    styleSrc: [
      '\'self\'',
      '\'unsafe-inline\'',
      'https://www.google.com',
      'fonts.googleapis.com',
      'https://api.tiles.mapbox.com',
      'https://s.ytimg.com',
      'https://pontoon.mozilla.org'
    ],
    imgSrc: [
      '\'self\'',
      '\'unsafe-inline\'',
      '*'
    ],
    connectSrc: [
      '\'self\'',
      'https://www.google.com',
      '*.tiles.mapbox.com',
      '*.log.optimizely.com',
      '*.mywebmaker.org',
      '*.makes.org',
      'bitly.mofoprod.net',
      'https://pontoon.mozilla.org',
      process.env.TEACH_API_URL || 'https://teach-api.herokuapp.com',
      url.parse(process.env.NEWSLETTER_MAILINGLIST_URL || 'https://basket-dev.allizom.org').hostname
    ]
  },
  reportOnly: false,
  browserSniff: false
}));

app.use(helmet.xssFilter({
  setOnOldIE: true
}));

app.use(helmet.frameguard({
  action: 'deny'
}));

app.use(helmet.hsts({
  maxAge: 1000 * 60 * 60 * 24 * 90
}));

app.use(helmet.ieNoOpen());

app.use(helmet.noSniff());

if (process.env.HPKP) {
  app.use(helmet.hpkp({
    maxAge: 1000 * 60 * 60 * 24 * 90,
    sha256s: process.env.HPKP.split(' '),
    setIf: function (req, res) {
      return req.secure;
    }
  }));
}

/**
 * Wait for the router to come online.
 */
app.use(function(req, res, next) {
  if (router) {
    return next();
  }
  res.send('Please wait while the server-side bundle regenerates.');
});

/**
 * If we have a router, check if we're dealing with a redirect.
 */
app.use(function(req, res, next) {
  var url = urlToRoutePath(req.path);
  if (!indexStatic.REDIRECTS[url]) {
    return next();
  }
  res.redirect('/' + indexStatic.REDIRECTS[url] + '/');
});

/**
 * If it's not a redirect, is it a component page?
 */
app.use(function(req, res, next) {
  var routes = indexStatic.routes;
  var location = urlToRoutePath(req.url);
  var urls = indexStatic.URLS;

  if (!matcher) {
    matcher = routington();
    urls.forEach(function(route) { matcher.define(route); });
  }

  match({ routes: routes, location: location}, function resolveRoute(err, redirect, props) {
    // is this even a component?
    if ( !props ) {
      return next();
    }

    // if this belongs to one of the predefined urls, let's generate its associated page
    if ( matcher.match(location) ) {
      var search = url.parse(req.url).search || "";

      locale = localize.parseLocale(req.headers["accept-language"], location, locales).locale;
      if (location === "/") {
        res.redirect(302, location + locale + search);
        return;
      }
      return renderComponentPage(location,res);
    }

    // if neither of those, this is wordpress content
    else {
      // check to see a page with this slug exists on the WordPress site
      WpPageChecker(location, function(error, wpContent) {
        if ( error ) {
          return next();
        }
        // WP page exists, let's load the WordPress content through a component page
        return renderComponentPage(location,res);
      });
    }
  });
});

function renderComponentPage(location, res) {
  indexStatic.generate(location, {}, function(err, location, title, html) {
    if (err) {
      next(err);
    }
    res.type('html').send(html);
  });
}

/**
 * codemoji redirect - https://github.com/mozilla/codemoji
 */
app.use('/codemoji', function(req, res) {
  var location = url.parse(CODEMOJI_URL);
  location.pathname = req.path;
  location.query = req.query;
  res.redirect(307, url.format(location));
});

/**
 * Is this a static asset?
 */
app.use(express.static(DIST_DIR));

/**
* Maybe it is a route, but needs the localized path
*/
app.use(function(req, res, next) {
  var location = url.parse(req.url).pathname;
  var search = url.parse(req.url).search || "";
  // Get a valid locale from the path and header
  var parsed = localize.parseLocale(req.headers["accept-language"], location, locales);
  var parsedLocale = parsed.locale;
  var parsedRedirect = parsed.redirect;
  // See if we should redirect.
  if (parsedRedirect) {
    res.redirect(301, "/" + parsedLocale + parsedRedirect + search);
  } else {
    next();
  }
})

app.use(function(req, res, next) {
  res.status(404).send(notFoundHTML);
});

app.DIST_DIR = DIST_DIR;
app.updateIndexStatic = updateIndexStatic;
module.exports = app;

if (!module.parent) {
  console.log('Initializing server.');

  if (PRODUCTION) {
    startProdApp();
  } else {
    console.log([
      'This server can only be run as a script when NODE_ENV="production".',
      'To run it in development mode, please use "npm run app".'
    ].join('\n'));
    process.exit(1);
  }
}
<commit_msg>Add another domain to CSP for Pontoon<commit_after>var path = require('path');
var fs = require('fs');
var express = require('express');
var helmet = require('helmet');
var url = require('url');

var React = require('react');
var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var match = ReactRouter.match;
var routington = require('routington');

var indexStaticWatcher = require('./lib/build/index-static-watcher').create();
var PORT = process.env.PORT || 8008;
var PRODUCTION = (process.env.NODE_ENV === 'production');
var DIST_DIR = path.join(__dirname, 'dist');
var CODEMOJI_URL = process.env.CODEMOJI_URL || "https://codemoji.mofostaging.net";
var localize = require('mofo-localize');

var WpPageChecker = require('./lib/wp-page-checker');

var habitat = require('habitat');
habitat.load('.env');

var indexStatic;
var router;
var matcher;
var app = express();
var locale = "";
var locales = require('./dist/locales.json')

app.disable('x-powered-by');

var notFoundHTML = [
  '<!doctype html>',
  '',
  '<meta charset="utf-8">',
  '<title>404 - Page not found</title>',
  '',
  '
404 - Page not found
',
  ''
].join('');

var urlToRoutePath = function(loc) {
  // For router-resolution, we don't want hashes...
  var pos = loc.indexOf('#');
  if (pos > -1) { loc = loc.substring(0,pos); }
  // And we don't want query strings, either...
  pos = loc.indexOf('?');
  if (pos > -1) { loc = loc.substring(0,pos); }
  // If this is not the site root, we need to remove the leading slash.
  if (loc !== '/') {
    loc = loc.replace(/^\//, '').replace(/\/$/, '');
  }
  return loc;
};

var startProdApp = function() {
  console.log([
    'Production mode enabled. Note that "npm install" is assumed to',
    'have recently been run with NODE_ENV="production". If this is not',
    'the case, some or all static assets may be out of date.'
  ].join('\n'));
  indexStaticWatcher.build(function(err, newIndexStatic) {
    if (err) {
      throw err;
    }

    console.log('Built server-side bundle.');
    updateIndexStatic(newIndexStatic);
    app.listen(PORT, function() {
      console.log('Listening on port', PORT);
    });
  });
};

var updateIndexStatic = function(newIndexStatic) {
  indexStatic = newIndexStatic;
  router = indexStatic ? React.createElement(Router, {routes: indexStatic.routes}) : null;
};

// make sure the dir we'll be using for static hosting exists.
if (!fs.existsSync(DIST_DIR)) {
  fs.mkdirSync(DIST_DIR);
}

/**
 * Security Headers
 */
 var securityHeaders = {
  directives: {
    defaultSrc: [
      'www.youtube.com',
      'https://public.etherpad-mozilla.org'
    ],
    scriptSrc: [
      '\'self\'',
      '\'unsafe-inline\'',
      '\'unsafe-eval\'',
      'data:',
      'www.google-analytics.com',
      'cdn.optimizely.com',
      'https://www.google.com',
      'https://s.ytimg.com',
      'https://www.mozilla.org'
    ],
    fontSrc: [
      '\'self\'',
      'fonts.googleapis.com',
      'fonts.gstatic.com'
    ],
    styleSrc: [
      '\'self\'',
      '\'unsafe-inline\'',
      'https://www.google.com',
      'fonts.googleapis.com',
      'https://api.tiles.mapbox.com',
      'https://s.ytimg.com'
    ],
    imgSrc: [
      '\'self\'',
      '\'unsafe-inline\'',
      '*'
    ],
    connectSrc: [
      '\'self\'',
      'https://www.google.com',
      '*.tiles.mapbox.com',
      '*.log.optimizely.com',
      '*.mywebmaker.org',
      '*.makes.org',
      'bitly.mofoprod.net',
      process.env.TEACH_API_URL || 'https://teach-api.herokuapp.com',
      url.parse(process.env.NEWSLETTER_MAILINGLIST_URL || 'https://basket-dev.allizom.org').hostname
    ]
  },
  reportOnly: false,
  browserSniff: false
};

if (process.env.ENABLE_PONTOON) {
  securityHeaders.directives.defaultSrc.push('https://pontoon.mozilla.org', 'https://mozilla-pontoon-staging.herokuapp.com');
  securityHeaders.directives.scriptSrc.push('https://pontoon.mozilla.org', 'https://mozilla-pontoon-staging.herokuapp.com');
  securityHeaders.directives.fontSrc.push('https://pontoon.mozilla.org', 'https://mozilla-pontoon-staging.herokuapp.com');
  securityHeaders.directives.styleSrc.push('https://pontoon.mozilla.org', 'https://mozilla-pontoon-staging.herokuapp.com');
  securityHeaders.directives.connectSrc.push('https://pontoon.mozilla.org', 'https://mozilla-pontoon-staging.herokuapp.com');
}
app.use(helmet.contentSecurityPolicy(securityHeaders));

app.use(helmet.xssFilter({
  setOnOldIE: true
}));

app.use(helmet.frameguard({
  action: 'deny'
}));

app.use(helmet.hsts({
  maxAge: 1000 * 60 * 60 * 24 * 90
}));

app.use(helmet.ieNoOpen());

app.use(helmet.noSniff());

if (process.env.HPKP) {
  app.use(helmet.hpkp({
    maxAge: 1000 * 60 * 60 * 24 * 90,
    sha256s: process.env.HPKP.split(' '),
    setIf: function (req, res) {
      return req.secure;
    }
  }));
}

/**
 * Wait for the router to come online.
 */
app.use(function(req, res, next) {
  if (router) {
    return next();
  }
  res.send('Please wait while the server-side bundle regenerates.');
});

/**
 * If we have a router, check if we're dealing with a redirect.
 */
app.use(function(req, res, next) {
  var url = urlToRoutePath(req.path);
  if (!indexStatic.REDIRECTS[url]) {
    return next();
  }
  res.redirect('/' + indexStatic.REDIRECTS[url] + '/');
});

/**
 * If it's not a redirect, is it a component page?
 */
app.use(function(req, res, next) {
  var routes = indexStatic.routes;
  var location = urlToRoutePath(req.url);
  var urls = indexStatic.URLS;

  if (!matcher) {
    matcher = routington();
    urls.forEach(function(route) { matcher.define(route); });
  }

  match({ routes: routes, location: location}, function resolveRoute(err, redirect, props) {
    // is this even a component?
    if ( !props ) {
      return next();
    }

    // if this belongs to one of the predefined urls, let's generate its associated page
    if ( matcher.match(location) ) {
      var search = url.parse(req.url).search || "";

      locale = localize.parseLocale(req.headers["accept-language"], location, locales).locale;
      if (location === "/") {
        res.redirect(302, location + locale + search);
        return;
      }
      return renderComponentPage(location,res);
    }

    // if neither of those, this is wordpress content
    else {
      // check to see a page with this slug exists on the WordPress site
      WpPageChecker(location, function(error, wpContent) {
        if ( error ) {
          return next();
        }
        // WP page exists, let's load the WordPress content through a component page
        return renderComponentPage(location,res);
      });
    }
  });
});

function renderComponentPage(location, res) {
  indexStatic.generate(location, {}, function(err, location, title, html) {
    if (err) {
      next(err);
    }
    res.type('html').send(html);
  });
}

/**
 * codemoji redirect - https://github.com/mozilla/codemoji
 */
app.use('/codemoji', function(req, res) {
  var location = url.parse(CODEMOJI_URL);
  location.pathname = req.path;
  location.query = req.query;
  res.redirect(307, url.format(location));
});

/**
 * Is this a static asset?
 */
app.use(express.static(DIST_DIR));

/**
* Maybe it is a route, but needs the localized path
*/
app.use(function(req, res, next) {
  var location = url.parse(req.url).pathname;
  var search = url.parse(req.url).search || "";
  // Get a valid locale from the path and header
  var parsed = localize.parseLocale(req.headers["accept-language"], location, locales);
  var parsedLocale = parsed.locale;
  var parsedRedirect = parsed.redirect;
  // See if we should redirect.
  if (parsedRedirect) {
    res.redirect(301, "/" + parsedLocale + parsedRedirect + search);
  } else {
    next();
  }
})

app.use(function(req, res, next) {
  res.status(404).send(notFoundHTML);
});

app.DIST_DIR = DIST_DIR;
app.updateIndexStatic = updateIndexStatic;
module.exports = app;

if (!module.parent) {
  console.log('Initializing server.');

  if (PRODUCTION) {
    startProdApp();
  } else {
    console.log([
      'This server can only be run as a script when NODE_ENV="production".',
      'To run it in development mode, please use "npm run app".'
    ].join('\n'));
    process.exit(1);
  }
}
<|endoftext|>


<commit_before>/**
 *    Author: Michael
 *    1 Sentence Diary implementation using node and telegram
 *
*/

var _ = require('lodash'); // libary just incase.
// var colors = require('colors')
var argv = require('minimist')(process.argv.slice(2));
var db = require('./lib/db');

if (!argv.debug) {
  var tg = require('./tg').start();
}
var statics = require('./lib/statics');

/* *********************************************************************
      Commands
*/

var ErrorMsg = function ErrorMsg (user, str) {
  tg.send(user,
   'Detected too many or invalid words in your <' + str + '> command. ' +
   'Use \"<help> <' + str + '> for more detail\"');
};

var FailMsg = function FailMsg (user, str) {
  tg.send(user,
   'Your <' + str + '> command failed to run for some reason.' +
   'Please try again or log an issue on this project\'s github page.');
};

var keywords = {
  '<help>': function helpCommand (msg) {
    var str = 'Send your diary sentences to this account and we will store them for you! ' +
              'Other commands include: <removeAllData>, <generateview>, <stats> and <date>. ' +
              'In order to see what they do send both <help> and a command in a message. For ' +
              'example: "<help> <generateview>" would give help about the <generateview> command.';
    tg.send(msg.from.print_name, str);
  },
  '<removealldata>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<generateview>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<stats>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<date>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<reminder>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
    return;

    /** THE BELOW IS UNUSED CODE RESERVED FOR LATER USE **/
    // Validate the message
    var words = msg.text.split(' ');
    var time = (words[0] === '<reminder>') ? words[1] : words[0]; // only expecting 2 words

    // Check that time is a number
    if (isNaN(time)) return ErrorMsg('reminder');

    time = parseInt(time); // convert to time number
    if (~~(time / 100) >= 24 || time - (~~(time / 100) * 100) >= 60) {// ensure that it's a valid 24hour time
      time = new Date(0, 0, 0, ~~(time / 100), time - (~~(time / 100) * 100));
    }

    // Do the stuff
    switch (words.length) {
      case 1: // Reset a time
        reminders.setReminder(msg.from.print_name, false, function (err) {
          if (!err) {
            tg.send(msg.from.print_name, 'You have disabled daily reminders');
            // reminders.removeUser(msg.from.print_name)
          } else FailMsg('reminder');
        });
        break;
      case 2: // Included a time
        reminders.setReminder(msg.from.print_name, time, function (err) {
          if (!err) {
            tg.send(msg.from.print_name, 'You will now be reminded at ' + time.getHours() + ':' + time.getMinutes() +
              ' each day. To remove this reminder send \"<reminder>\" as a message.');
            // reminders.addUser(msg.from.print_name, time)
          } else FailMsg('reminder');
        });
        break;
      default:
        return ErrorMsg('reminder');
    }
  }
};

/* *********************************************************************
      Listeners
*/

tg.event.on('started', function (d) {
  console.log('yo, this dawg is kicking');
});

tg.event.on('newmessage', function (m) {
  console.log('-------------------------------------'.magenta);
  console.log(('we got a message from ' + m.from.first_name).cyan);

  // Check if a new user here TODO
  // Check user id against those in db and then send welcome message if not there
  // Then return early
  db.dbGetUser(m.from.id, function (err, doc) {
    if (err) console.err('Ran into an error when checking if user exists');
    console.log('doc: ' + require('util').inspect(doc, { depth: null }));
    if (doc === null) { // This is a new user
      db.dbAddUser(m.from);
      tg.send(m.from.print_name, 'Hi! Welcome to Cavejay\'s Single Sentence Diary Implementation. ' +
        ' Type \"<help>\" to get started!');
    }
  });

  // Check for keywords&commands
  var words = m.text.replace('.', ' ').split(' ');
  var caughtCommands = [];

  words.forEach(function (word) {
    if (word.toLowerCase() in keywords) caughtCommands.push(word.toLowerCase());
  });
  console.log('The following commands were caught:\n' + caughtCommands);

  // There was nothing so this must be a diary entry
  if (caughtCommands.length === 0) { // No commands
    db.dbAddEntry(m.from.id, m.text, +new Date());

    // Strip the white space. It'll kill the message
    m.text = m.text.replace(/\r?\n|\r/g, ' ');
    tg.send(m.from.print_name, 'A new diary entry was added saying: "' + m.text + '"');

  // We caught a specific help command
  } else if (caughtCommands.length === 2 && caughtCommands.indexOf('<help>') >= 0) {
    // Find out what the other command is and send it's help message back.
    var helpPos = caughtCommands.indexOf('<help>');
    var otherCommandPos = (helpPos === 0) ? 1 : 0;
    console.log('returning help message for ' + caughtCommands[otherCommandPos]);
    tg.send(m.from.print_name, statics.helpStrings[caughtCommands[otherCommandPos]]);

  // We caught a single command and are running it
  } else if (caughtCommands.length === 1) { // run the first command
    // run the commands function
    keywords[caughtCommands[0]](m);

  // Incase they went nuts with the commands nothing happens and they get a note.
  } else {
    tg.send(m.from.print_name, 'Too many commands were detected. ' +
    'Please only send 1, or 2 when using the <help> command');
  }
});

tg.event.on('longMessage', function (d) {
  console.log('We got a long message:'.cyan);
  console.log(d);
});

tg.event.on('unknownString', function (d) {
  console.log('Caught an unknown string'.red);
  console.log(d);
});

tg.event.on('sentmessage', function (d) {
  console.log('A message was sent'.cyan);
});

tg.event.on('other', function (d) {
  console.log('Someother type of message was caught'.cyan);
  console.log(d);
});

tg.event.on('readReceipt', function (d) {
  console.log('User '.cyan + d.toString().cyan + ' just triggered a read receipt'.cyan);
});

process.stdin.on('readable', function () {
  var chunk = process.stdin.read();
  if (chunk !== null) {
    process.stdout.write('sending: "' + chunk.toString().trim() + '"\n');
    tg.write(chunk.toString().trim());
  }
});

process.on('exit', function (code) {
  tg.close();
});

/* *************************************************************************
      Functions
*/
<commit_msg>pre merge fixes<commit_after>/**
 *    Author: Michael
 *    1 Sentence Diary implementation using node and telegram
 *
*/

var _ = require('lodash'); // libary just incase.
// var colors = require('colors')
var argv = require('minimist')(process.argv.slice(2));
var db = require('./lib/db');

if (!argv.debug) {
  var tg = require('./tg').start();
}
var statics = require('./lib/statics');

/* *********************************************************************
      Commands
*/

var ErrorMsg = function ErrorMsg (user, str) {
  tg.send(user,
   'Detected too many or invalid words in your <' + str + '> command. ' +
   'Use \"<help> <' + str + '> for more detail\"');
};

var FailMsg = function FailMsg (user, str) {
  tg.send(user,
   'Your <' + str + '> command failed to run for some reason.' +
   'Please try again or log an issue on this project\'s github page.');
};

var keywords = {
  '<help>': function helpCommand (msg) {
    var str = 'Send your diary sentences to this account and we will store them for you! ' +
              'Other commands include: <removeAllData>, <generateview>, <stats> and <date>. ' +
              'In order to see what they do send both <help> and a command in a message. For ' +
              'example: "<help> <generateview>" would give help about the <generateview> command.';
    tg.send(msg.from.print_name, str);
  },
  '<removealldata>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<generateview>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<stats>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<date>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
  },
  '<reminder>': function (msg) {
    var str = 'NOT CURRENTLY IMPLEMENTED. ';
    tg.send(msg.from.print_name, str);
    return;

    /** THE BELOW IS UNUSED CODE RESERVED FOR LATER USE **/
    // Validate the message
    var words = msg.text.split(' ');
    var time = (words[0] === '<reminder>') ? words[1] : words[0]; // only expecting 2 words

    // Check that time is a number
    if (isNaN(time)) return ErrorMsg('reminder');

    time = parseInt(time); // convert to time number
    if (~~(time / 100) >= 24 || time - (~~(time / 100) * 100) >= 60) {// ensure that it's a valid 24hour time
      time = new Date(0, 0, 0, ~~(time / 100), time - (~~(time / 100) * 100));
    }

    // Do the stuff
    switch (words.length) {
      case 1: // Reset a time
        reminders.setReminder(msg.from.print_name, false, function (err) {
          if (!err) {
            tg.send(msg.from.print_name, 'You have disabled daily reminders');
            // reminders.removeUser(msg.from.print_name)
          } else FailMsg('reminder');
        });
        break;
      case 2: // Included a time
        reminders.setReminder(msg.from.print_name, time, function (err) {
          if (!err) {
            tg.send(msg.from.print_name, 'You will now be reminded at ' + time.getHours() + ':' + time.getMinutes() +
              ' each day. To remove this reminder send \"<reminder>\" as a message.');
            // reminders.addUser(msg.from.print_name, time)
          } else FailMsg('reminder');
        });
        break;
      default:
        return ErrorMsg('reminder');
    }
  }
};

/* *********************************************************************
      Listeners
*/

tg.event.on('started', function (d) {
  console.log('yo, this dawg is kicking');
});

tg.event.on('newmessage', function (m) {
  console.log('-------------------------------------'.magenta);
  console.log(('we got a message from ' + m.from.first_name).cyan);

  // Check if a new user here TODO
  // Check user id against those in db and then send welcome message if not there
  // Then return early
  db.dbGetUser(m.from.id, function (err, doc) {
    if (err) console.err('Ran into an error when checking if user exists'.red);
    // console.log('doc: ' + require('util').inspect(doc, { depth: null }));
    if (doc === null) { // This is a new user
      console.log((m.from.first_name + ' is a new user. We\'re sending them a message').cyan);
      db.dbAddUser(m.from);
      tg.send(m.from.print_name, 'Hi! Welcome to Cavejay\'s Single Sentence Diary Implementation. ' +
        ' Type \"<help>\" to get started!');
    }
  });

  // Check for keywords&commands
  var words = m.text.replace('.', ' ').split(' ');
  var caughtCommands = [];

  words.forEach(function (word) {
    if (word.toLowerCase() in keywords) caughtCommands.push(word.toLowerCase());
  });
  console.log('The following commands were caught:\n' + caughtCommands);

  // There was nothing so this must be a diary entry
  if (caughtCommands.length === 0) { // No commands
    db.dbAddEntry(m.from.id, m.text, +new Date());

    // Strip the white space. It'll kill the message
    m.text = m.text.replace(/\r?\n|\r/g, ' ');
    tg.send(m.from.print_name, 'A new diary entry was added saying: "' + m.text + '"');

  // We caught a specific help command
  } else if (caughtCommands.length === 2 && caughtCommands.indexOf('<help>') >= 0) {
    // Find out what the other command is and send it's help message back.
    var helpPos = caughtCommands.indexOf('<help>');
    var otherCommandPos = (helpPos === 0) ? 1 : 0;
    console.log('returning help message for ' + caughtCommands[otherCommandPos]);
    tg.send(m.from.print_name, statics.helpStrings[caughtCommands[otherCommandPos]]);

  // We caught a single command and are running it
  } else if (caughtCommands.length === 1) { // run the first command
    // run the commands function
    keywords[caughtCommands[0]](m);

  // Incase they went nuts with the commands nothing happens and they get a note.
  } else {
    tg.send(m.from.print_name, 'Too many commands were detected. ' +
    'Please only send 1, or 2 when using the <help> command');
  }
});

tg.event.on('longMessage', function (d) {
  console.log('We got a long message:'.cyan);
  console.log(d);
});

tg.event.on('unknownString', function (d) {
  console.log('Caught an unknown string'.red);
  console.log(d);
});

tg.event.on('sentmessage', function (d) {
  console.log('A message was sent'.cyan);
});

tg.event.on('other', function (d) {
  console.log('Someother type of message was caught'.cyan);
  console.log(d);
});

tg.event.on('readReceipt', function (d) {
  console.log('User '.cyan + d.toString().cyan + ' just triggered a read receipt'.cyan);
});

process.stdin.on('readable', function () {
  var chunk = process.stdin.read();
  if (chunk !== null) {
    process.stdout.write('sending: "' + chunk.toString().trim() + '"\n');
    tg.write(chunk.toString().trim());
  }
});

process.on('exit', function (code) {
  tg.close();
});

/* *************************************************************************
      Functions
*/
<|endoftext|>


<commit_before>// See https://github.com/yagop/node-telegram-bot-api
var TelegramBot = require('node-telegram-bot-api');

// See https://github.com/t3chnoboy/amazon-product-api
var amazon = require('amazon-product-api');

// See https://github.com/vkurchatkin/which-country
var wc = require('which-country');

// See https://github.com/kemitchell/markdown-escape.js
var markdownEscape = require('markdown-escape')

// List of supported Amazon endpoints
var amazonEndpoints = {
  'US' : 'webservices.amazon.com',
  'CA' : 'webservices.amazon.ca',
  'IT' : 'webservices.amazon.it',
  'DE' : 'webservices.amazon.de',
  'UK' : 'webservices.amazon.co.uk',
  'ES' : 'webservices.amazon.es',
  'FR' : 'webservices.amazon.fr'
};

// Telegram API Token
var token = process.env.TELEGRAM_API_TOKEN || '';

// Create the Bot
var bot = new TelegramBot(
  token,
  {
    webHook: {
      port: process.env.PORT || '3000'
    }
  }
);

// Listen on WebHooks
bot
.setWebHook(
  process.env.BASE_URL + '/' + process.env.WEBHOOK_TOKEN
);

// Once the user is searching...
bot
.on( 'inline_query', function ( message ){
  if ( message.query ) {
    // Get the country where to query
    var query = message.query.split('@')[0],
        country = ( message.query.split('@')[1] || '').toUpperCase();

    // Detect user country if not provided
    if ( message.location ) {
      country = wc([
        message.location.latitude,
        message.location.longitude
      ]);
    }

    if ( !country )
      // Force the Amazon.com search if no country given or detected
      country = 'US';
    else
      // Get only the first two letters and convert them to uppercase
      country = country.toUpperCase().substring(0,2)

    // If the country is given, always check if it's in the list
    if ( country in amazonEndpoints ) {

      // Create the Amazon Client
      var client = amazon.createClient({
        awsId: process.env.AMAZON_ACCESS_ID || '',
        awsSecret: process.env.AMAZON_SECRET_ACCESS_KEY || '',
        awsTag: process.env['AMAZON_ASSOCIATE_TAG_' + country] || ''
      });

      client.itemSearch(
        {
          keywords: query,
          searchIndex: 'All',
          responseGroup: 'Images,ItemAttributes,OfferSummary',
          sort: 'relevance',
          domain: amazonEndpoints[ country ]
        },
        function (error, results) {
          if (error) {
            // Craft error message
            answerUser(
              message,
              [{
                type: 'article',
                id: '000',
                title: 'Unknown Error',
                input_message_content: {
                  message_text: "Sorry, something bad happened. Please try later :("
                },
                url: '',
                hide_url: true,
                thumb_url: '',
                thumb_width: 64,
                thumb_height: 64
              }]
            )
          } else {
            var answers = [];

            for ( var k in results ) {
              var item = results[k],
                  id = coalesce( item, k, 'ASIN', 0 ),
                  price = coalesce( item, null, 'OfferSummary', 0, 'LowestNewPrice', 0, 'FormattedPrice', 0 ),
                  price = ( price ? '[' + price + ']' : '' ),
                  url = coalesce( item, amazonEndpoints[ country ].replace('webservices.','https://'), 'DetailPageURL', 0 ),
                  title = coalesce( item, 'No Title', 'ItemAttributes', 0, 'Title', 0 ),
                  imageUrl = coalesce( item, amazonEndpoints[ country ].replace('webservices.','https://'), 'ImageSets', 0, 'ImageSet', 0, 'SmallImage', 0, 'URL', 0 ),
                  largeImageUrl = coalesce( item, amazonEndpoints[ country ].replace('webservices.','https://'), 'ImageSets', 0, 'ImageSet', 0, 'LargeImage', 0, 'URL', 0 ),
                  imageWidth = parseInt( coalesce( item, 0, 'ImageSets', 0, 'ImageSet', 0, 'SmallImage', 0, 'Width', 0, '_' ) ),
                  imageHeight = parseInt( coalesce( item, 0, 'ImageSets', 0, 'ImageSet', 0, 'SmallImage', 0, 'Height', 0, '_' ) );

              answers
              .push(
                {
                  type: 'article',
                  id: id,
                  title: price + title,
                  input_message_content: {
                    message_text: '[' + markdownEscape(title) + '](' + url + ')' + ( price ? '\n\n*Lowest Price:* ' + price : '' ) + ( largeImageUrl ? '\n\n*Large Image:* ' + largeImageUrl : '' ),
                    parse_mode: 'Markdown'
                  },
                  url: url,
                  hide_url: false,
                  thumb_url: imageUrl,
                  thumb_width: imageWidth,
                  thumb_height: imageHeight
                }
              );
            }

            answerUser(
              message,
              answers
            )
          }
        }
      )
    } else {
      // Craft unsupported message
      answerUser(
        message,
        [{
          type: 'article',
          id: '000',
          title: 'Unsupported country',
          input_message_content: {
            message_text: "Sorry, I do not support the country you're asking for :("
          },
          url: '',
          hide_url: true,
          thumb_url: '',
          thumb_width: 64,
          thumb_height: 64
        }]
      )
    }
  }
});

var answerUser = function ( message, answer ) {
  // Craft answer
  bot
  .answerInlineQuery(
    message.id,
    answer
  );
}

var coalesce = function ( arr, def ) {
    var i, max_i, ret = arr;

    for (i = 2, max_i = arguments.length; i < max_i; i++) {
        ret = ret[ arguments[i] ];
        if (ret === undefined) {
            ret = def;
            break;
        }
    }

    return ret;
}<commit_msg>Better error logging.<commit_after>// See https://github.com/yagop/node-telegram-bot-api
var TelegramBot = require('node-telegram-bot-api');

// See https://github.com/t3chnoboy/amazon-product-api
var amazon = require('amazon-product-api');

// See https://github.com/vkurchatkin/which-country
var wc = require('which-country');

// See https://github.com/kemitchell/markdown-escape.js
var markdownEscape = require('markdown-escape')

// List of supported Amazon endpoints
var amazonEndpoints = {
  'US' : 'webservices.amazon.com',
  'CA' : 'webservices.amazon.ca',
  'IT' : 'webservices.amazon.it',
  'DE' : 'webservices.amazon.de',
  'UK' : 'webservices.amazon.co.uk',
  'ES' : 'webservices.amazon.es',
  'FR' : 'webservices.amazon.fr'
};

// Telegram API Token
var token = process.env.TELEGRAM_API_TOKEN || '';

// Create the Bot
var bot = new TelegramBot(
  token,
  {
    webHook: {
      port: process.env.PORT || '3000'
    }
  }
);

// Listen on WebHooks
bot
.setWebHook(
  process.env.BASE_URL + '/' + process.env.WEBHOOK_TOKEN
);

// Once the user is searching...
bot
.on( 'inline_query', function ( message ){
  if ( message.query ) {
    // Get the country where to query
    var query = message.query.split('@')[0],
        country = ( message.query.split('@')[1] || '').toUpperCase();

    // Detect user country if not provided
    if ( message.location ) {
      country = wc([
        message.location.latitude,
        message.location.longitude
      ]);
    }

    if ( !country )
      // Force the Amazon.com search if no country given or detected
      country = 'US';
    else
      // Get only the first two letters and convert them to uppercase
      country = country.toUpperCase().substring(0,2)

    // If the country is given, always check if it's in the list
    if ( country in amazonEndpoints ) {

      // Create the Amazon Client
      var client = amazon.createClient({
        awsId: process.env.AMAZON_ACCESS_ID || '',
        awsSecret: process.env.AMAZON_SECRET_ACCESS_KEY || '',
        awsTag: process.env['AMAZON_ASSOCIATE_TAG_' + country] || ''
      });

      client.itemSearch(
        {
          keywords: query,
          searchIndex: 'All',
          responseGroup: 'Images,ItemAttributes,OfferSummary',
          domain: amazonEndpoints[ country ]
        },
        function (error, results) {
          if (error) {
            // Log the error
            console.log( error );
            // Craft error message
            answerUser(
              message,
              [{
                type: 'article',
                id: '000',
                title: 'Query error. Please retry with something different.',
                input_message_content: {
                  message_text: ''
                },
                url: '',
                hide_url: true,
                thumb_url: '',
                thumb_width: 64,
                thumb_height: 64
              }]
            )
          } else {
            var answers = [];

            for ( var k in results ) {
              var item = results[k],
                  id = coalesce( item, k, 'ASIN', 0 ),
                  price = coalesce( item, null, 'OfferSummary', 0, 'LowestNewPrice', 0, 'FormattedPrice', 0 ),
                  price = ( price ? '[' + price + ']' : '' ),
                  url = coalesce( item, amazonEndpoints[ country ].replace('webservices.','https://'), 'DetailPageURL', 0 ),
                  title = coalesce( item, 'No Title', 'ItemAttributes', 0, 'Title', 0 ),
                  imageUrl = coalesce( item, amazonEndpoints[ country ].replace('webservices.','https://'), 'ImageSets', 0, 'ImageSet', 0, 'SmallImage', 0, 'URL', 0 ),
                  largeImageUrl = coalesce( item, amazonEndpoints[ country ].replace('webservices.','https://'), 'ImageSets', 0, 'ImageSet', 0, 'LargeImage', 0, 'URL', 0 ),
                  imageWidth = parseInt( coalesce( item, 0, 'ImageSets', 0, 'ImageSet', 0, 'SmallImage', 0, 'Width', 0, '_' ) ),
                  imageHeight = parseInt( coalesce( item, 0, 'ImageSets', 0, 'ImageSet', 0, 'SmallImage', 0, 'Height', 0, '_' ) );

              answers
              .push(
                {
                  type: 'article',
                  id: id,
                  title: price + title,
                  input_message_content: {
                    message_text: '[' + markdownEscape(title) + '](' + url + ')' + ( price ? '\n\n*Lowest Price:* ' + price : '' ) + ( largeImageUrl ? '\n\n*Large Image:* ' + largeImageUrl : '' ),
                    parse_mode: 'Markdown'
                  },
                  url: url,
                  hide_url: false,
                  thumb_url: imageUrl,
                  thumb_width: imageWidth,
                  thumb_height: imageHeight
                }
              );
            }

            answerUser(
              message,
              answers
            )
          }
        }
      )
    } else {
      // Craft unsupported message
      answerUser(
        message,
        [{
          type: 'article',
          id: '000',
          title: 'Unsupported country',
          input_message_content: {
            message_text: ''
          },
          url: '',
          hide_url: true,
          thumb_url: '',
          thumb_width: 64,
          thumb_height: 64
        }]
      )
    }
  }
});

var answerUser = function ( message, answer ) {
  // Craft answer
  bot
  .answerInlineQuery(
    message.id,
    answer
  );
}

var coalesce = function ( arr, def ) {
    var i, max_i, ret = arr;

    for (i = 2, max_i = arguments.length; i < max_i; i++) {
        ret = ret[ arguments[i] ];
        if (ret === undefined) {
            ret = def;
            break;
        }
    }

    return ret;
}<|endoftext|>


<commit_before>var app = require('express')()
var http = require('http').Server(app)
var io = require('socket.io')(http)

var shortURLPromise
  , short = require('short');

// connect to mongodb
short.connect('mongodb://localhost/short');

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html')
})

io.on('connection', function (socket) {
  console.log("Someone connected")
  socket.on('url', function (msg) {
    var shortURLPromise = short.generate({ URL : msg })

    shortURLPromise.then(function(mongodbDoc) {
      console.log("Long: " + mongodbDoc.URL)
      console.log("Short: " + mongodbDoc.hash)
      io.emit('short', msg)
      short.retrieve(mongodbDoc.hash).then(function(result) {
        io.emit('long', result.hash)
      })
    })
  })
})

http.listen(3000, function () {
  console.log('listening on *:3000')
})
<commit_msg>change port<commit_after>var app = require('express')()
var http = require('http').Server(app)
var io = require('socket.io')(http)

var shortURLPromise
  , short = require('short');

// connect to mongodb
short.connect('mongodb://localhost/short');

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html')
})

io.on('connection', function (socket) {
  console.log("Someone connected")
  socket.on('url', function (msg) {
    var shortURLPromise = short.generate({ URL : msg })

    shortURLPromise.then(function(mongodbDoc) {
      console.log("Long: " + mongodbDoc.URL)
      console.log("Short: " + mongodbDoc.hash)
      io.emit('short', msg)
      short.retrieve(mongodbDoc.hash).then(function(result) {
        io.emit('long', result.hash)
      })
    })
  })
})

http.listen(3000, function () {
  console.log('listening on *:3004')
})
<|endoftext|>


<commit_before>'use strict';

let TelegramBot = require('node-telegram-bot-api');
var Firebase = require("firebase");
let request = require('request-promise');

let TelegramBotToken = process.env.TELEGRAM_BOT_TOKEN;
let telegramBot = new TelegramBot(TelegramBotToken, { polling: true });

let registeredUsers = [], currentTopStory;

function getTopStory(){
    return request('https://hacker-news.firebaseio.com/v0/topstories.json').then(data =>
        request('https://hacker-news.firebaseio.com/v0/item/' + JSON.parse(data)[0] + '.json?print=pretty')
    );
};

function pushTopStory(story){
    registeredUsers.forEach(user => telegramBot.sendMessage(user, story.title + ' - ' + story.url));
    currentTopStory = story.id;
}

setInterval(() => {
     getTopStory().then(data => {
        data = JSON.parse(data);

        if(data.id !== currentTopStory){
            pushTopStory(data);
        }
     });
}, 10000);

telegramBot.onText(/\/start/, msg => {
    registeredUsers.push(msg.from.id);
    telegramBot.sendMessage(msg.from.id, 'Thanks, you\'re now registered, you\'ll get a message when the top story changes!');
});
<commit_msg>Remove Firebase dependency<commit_after>'use strict';

let TelegramBot = require('node-telegram-bot-api');
let request = require('request-promise');

let TelegramBotToken = process.env.TELEGRAM_BOT_TOKEN;
let telegramBot = new TelegramBot(TelegramBotToken, { polling: true });

let registeredUsers = [], currentTopStory;

function getTopStory(){
    return request('https://hacker-news.firebaseio.com/v0/topstories.json').then(data =>
        request('https://hacker-news.firebaseio.com/v0/item/' + JSON.parse(data)[0] + '.json?print=pretty')
    );
};

function pushTopStory(story){
    registeredUsers.forEach(user => telegramBot.sendMessage(user, story.title + ' - ' + story.url));
    currentTopStory = story.id;
}

setInterval(() => {
     getTopStory().then(data => {
        data = JSON.parse(data);

        if(data.id !== currentTopStory){
            pushTopStory(data);
        }
     });
}, 10000);

telegramBot.onText(/\/start/, msg => {
    registeredUsers.push(msg.from.id);
    telegramBot.sendMessage(msg.from.id, 'Thanks, you\'re now registered, you\'ll get a message when the top story changes!');
});
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var csrf = require('csurf');
var uuid = require('node-uuid');

var routes = require('./routes/index');
var users = require('./routes/users');
var userRoute = require('./routes/user-login');
var securityManager = require('./routes/security-home');
var roleRoute = require('./routes/role');

var UserAccountManager = require('./routes/lib/sec/UserAccountManager');
var RoleManager = require('./routes/lib/sec/RoleManager');
//var SavedGenericEntity = require('./lib/GenericEntityModel');
RoleManager.init();

RoleManager.buildCache();   // For future role optimizations

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(session(
  {secret: uuid.v4(), resave: false, saveUninitialized: true} // Generate random secret.
));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(csrf());
// csurf error handler: https://github.com/expressjs/csurf
app.use(function (err, req, res, next) {
    next();
    return;
  if (err.code !== 'EBADCSRFTOKEN') return next(err)

  // handle CSRF token errors here
  res.status(403)
  res.send('Session has expired or form tampered with')
});

app.all('/instance/*', function(req, res, next) { // Instance operations
    var account = req.session.account;
    if(!account) {
        res.status(403).send({error: "LoginRequired", errorCode: 403});
        return;
    }

    var userFoundCallback = function(user) {
        req.session.account = user; // Update session.
        console.log(req.method);
        var allowsOperation = '';
        if(req.method == 'GET') {
            allowsOperation = 'r';
        } else if(req.method == 'POST') {
            allowsOperation = 'c';
        } else if(req.method == 'PUT') {
            allowsOperation = 'u';
        } else if(req.method == "DELETE") {
            allowsOperation = 'd';
        } else {
            res.status(403).send({error: "AccessDeniedError", errorCode: 403});
            return;
        }
        console.log(allowsOperation);
        var hasRoleCallback = function(user, userRole, role) {
            var regex = /\/instance\/([A-Za-z_0-9]+)\//i;
            var regex2 = /\/instance\/([A-Za-z_0-9]+)/i;
            var path = req.path;
            var matches = regex.exec(path) || regex2.exec(path);
            var entity = matches[1];
            //console.log("Trying to match " + userRole.affects + " with " + entity);
            if((userRole && RegExp(userRole.affects).test(entity) == true) || user.isAdmin == true) {
                next();
            } else {
                res.status(403).send({error: "AccessDeniedError", errorCode: 403});
                return;
            }
        }

        var doesNotHaveRoleCallback = function() {
            res.status(403).send({error: "AccessDeniedError", errorCode: 403});
            return;
        }

        RoleManager.hasRole(account.accountId, "instance", allowsOperation, account._id, hasRoleCallback, doesNotHaveRoleCallback);
    }

    var userNotFoundCallback = function() {
        res.status(404).send({error: "UserNotFoundError", errorCode: 404});
        return;
    }

    UserAccountManager.doesUserExist(account.accountId, account.username, userFoundCallback, userNotFoundCallback);
});

app.all('/createEntity*', function(req, res, next) { // Instance operations
    var account = req.session.account;
    if(!account) {
        res.status(403).send({error: "LoginRequired", errorCode: 403});
        return;
    }

    var userFoundCallback = function(user) {

        var hasRoleCallback = function(user, userRole, role) {
            if (userRole) {
                var entityName = req.body.entityName;
                if (RegExp(userRole.affects).test(entityName) == true || user.isAdmin == true) {
                    next();
                } else {
                    res.status(403).send({error: "AccessDeniedError", errorCode: 403});
                    return;
                }
            } else if(user && user.isAdmin == true) {
                next();
            } else {
                res.status(403).send({error: "AccessDeniedError", errorCode: 403});
                return;
            }
        }

        var doesNotHaveRoleCallback = function() {
            res.status(403).send({error: "AccessDeniedError", errorCode: 403});
            return;
        }

        RoleManager.hasRole(account.accountId, "entity", "c", account._id, hasRoleCallback, doesNotHaveRoleCallback);
    }

    var userNotFoundCallback = function() {
        res.status(404).send({error: "UserNotFoundError", errorCode: 404});
        return;
    }

    UserAccountManager.doesUserExist(account.accountId, account.username, userFoundCallback, userNotFoundCallback);
});

// Read Entity auth is handled separately.
app.use('/', routes);
app.use('/users', users);
app.use('/user', userRoute);
app.use('/security-manager', securityManager);
app.use('/role', roleRoute);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;
<commit_msg>Now hosting api docs.<commit_after>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var csrf = require('csurf');
var uuid = require('node-uuid');

var routes = require('./routes/index');
var users = require('./routes/users');
var userRoute = require('./routes/user-login');
var securityManager = require('./routes/security-home');
var roleRoute = require('./routes/role');

var UserAccountManager = require('./routes/lib/sec/UserAccountManager');
var RoleManager = require('./routes/lib/sec/RoleManager');
//var SavedGenericEntity = require('./lib/GenericEntityModel');
RoleManager.init();

RoleManager.buildCache();   // For future role optimizations

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(session(
  {secret: uuid.v4(), resave: false, saveUninitialized: true} // Generate random secret.
));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(csrf());
// csurf error handler: https://github.com/expressjs/csurf
app.use(function (err, req, res, next) {
    next();
    return;
  if (err.code !== 'EBADCSRFTOKEN') return next(err)

  // handle CSRF token errors here
  res.status(403)
  res.send('Session has expired or form tampered with')
});

app.use('/apidocs', express.static(__dirname + '/public/documentation/apidoc'));

app.all('/instance/*', function(req, res, next) { // Instance operations
    var account = req.session.account;
    if(!account) {
        res.status(403).send({error: "LoginRequired", errorCode: 403});
        return;
    }

    var userFoundCallback = function(user) {
        req.session.account = user; // Update session.
        console.log(req.method);
        var allowsOperation = '';
        if(req.method == 'GET') {
            allowsOperation = 'r';
        } else if(req.method == 'POST') {
            allowsOperation = 'c';
        } else if(req.method == 'PUT') {
            allowsOperation = 'u';
        } else if(req.method == "DELETE") {
            allowsOperation = 'd';
        } else {
            res.status(403).send({error: "AccessDeniedError", errorCode: 403});
            return;
        }
        console.log(allowsOperation);
        var hasRoleCallback = function(user, userRole, role) {
            var regex = /\/instance\/([A-Za-z_0-9]+)\//i;
            var regex2 = /\/instance\/([A-Za-z_0-9]+)/i;
            var path = req.path;
            var matches = regex.exec(path) || regex2.exec(path);
            var entity = matches[1];
            //console.log("Trying to match " + userRole.affects + " with " + entity);
            if((userRole && RegExp(userRole.affects).test(entity) == true) || user.isAdmin == true) {
                next();
            } else {
                res.status(403).send({error: "AccessDeniedError", errorCode: 403});
                return;
            }
        }

        var doesNotHaveRoleCallback = function() {
            res.status(403).send({error: "AccessDeniedError", errorCode: 403});
            return;
        }

        RoleManager.hasRole(account.accountId, "instance", allowsOperation, account._id, hasRoleCallback, doesNotHaveRoleCallback);
    }

    var userNotFoundCallback = function() {
        res.status(404).send({error: "UserNotFoundError", errorCode: 404});
        return;
    }

    UserAccountManager.doesUserExist(account.accountId, account.username, userFoundCallback, userNotFoundCallback);
});

app.all('/createEntity*', function(req, res, next) { // Instance operations
    var account = req.session.account;
    if(!account) {
        res.status(403).send({error: "LoginRequired", errorCode: 403});
        return;
    }

    var userFoundCallback = function(user) {

        var hasRoleCallback = function(user, userRole, role) {
            if (userRole) {
                var entityName = req.body.entityName;
                if (RegExp(userRole.affects).test(entityName) == true || user.isAdmin == true) {
                    next();
                } else {
                    res.status(403).send({error: "AccessDeniedError", errorCode: 403});
                    return;
                }
            } else if(user && user.isAdmin == true) {
                next();
            } else {
                res.status(403).send({error: "AccessDeniedError", errorCode: 403});
                return;
            }
        }

        var doesNotHaveRoleCallback = function() {
            res.status(403).send({error: "AccessDeniedError", errorCode: 403});
            return;
        }

        RoleManager.hasRole(account.accountId, "entity", "c", account._id, hasRoleCallback, doesNotHaveRoleCallback);
    }

    var userNotFoundCallback = function() {
        res.status(404).send({error: "UserNotFoundError", errorCode: 404});
        return;
    }

    UserAccountManager.doesUserExist(account.accountId, account.username, userFoundCallback, userNotFoundCallback);
});

// Read Entity auth is handled separately.
app.use('/', routes);
app.use('/users', users);
app.use('/user', userRoute);
app.use('/security-manager', securityManager);
app.use('/role', roleRoute);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;
<|endoftext|>


<commit_before>import express from 'express';
import logger from 'morgan';
import bodyParser from 'body-parser';
import passport from 'passport';
import routes from './server/routes';

const app = express();
const http = require('http');

const port = parseInt(process.env.PORT, 10) || 8080;
app.use(logger('dev'));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session());
routes(app);

const server = http.createServer(app);
server.listen(port, () => console.log('The server is running on port 8080'));
<commit_msg>fix eslint errors<commit_after>import express from 'express';
import logger from 'morgan';
import bodyParser from 'body-parser';
import passport from 'passport';
import http from 'http';
import routes from './server/routes';

const app = express();
const port = parseInt(process.env.PORT, 10) || 8080;

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session());
routes(app);

const server = http.createServer(app);
server.listen(port, () => console.log('The server is running on port 8080'));
<|endoftext|>