<commit_before>import 'newrelic'
import http from 'http'
import express from 'express'
import winston from 'winston'
import expressWinston from 'express-winston'
import cors from 'cors'
import compression from 'compression'
import helmet from 'helmet'
import hpp from 'hpp'
import throng from 'throng'
import Raven from 'raven'
import dotenv from 'dotenv'
import path from 'path'
import aws from 'aws-sdk'
import pg from 'pg'
import EventEmitter from 'events'
import _ from 'lodash'
import fs from 'fs'
import os from 'os'

dotenv.config({ path: path.resolve(__dirname, '..', '.env') })

const DefaultServerConfig = {
  nodeEnv: process.env.NODE_ENV,
  port: process.env.PORT,
  timeout: 28000,
  accessKeyId: process.env.AWS_ACCESS_KEY_ID || 'xxx',
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || 'yyy',
  schemaName: process.env.SCHEMA_NAME,
  databaseUrl: process.env.DATABASE_URL || 'postgres://postgres@localhost/vivos-em-nos-pwa',
  sentryDns: process.env.SENTRY_DSN,
  s3BucketName: process.env.AWS_BUCKET || 'vivo-em-nos-staging',
}

class EmailEmitter extends EventEmitter {}

const createMemoriesListener = (client, emailEmitter) =>
  client.connect((err) => {
    if (err) throw err

    client.on('notification', (msg) => {
      emailEmitter.emit('memory_created', msg)
    })

    client.query('LISTEN new_memories')

    return client
    // client.end(function (err) {
    //   if (err) throw err
    // });
  })

// https://github.com/FastIT/health-check
const checkPostgres = (client) =>
  client.query('SELECT NOW() AS "the_time"', (err, res) => {
    if (err) {
      return ({ status: 'ko', online: false, error: err })
    }

    return {
      online: true,
      os: {
        arch: os.arch(),
        loadavg: os.loadavg(),
        freemem: os.freemem(),
        platform: os.platform(),
        totalmem: os.totalmem(),
        uptime: os.uptime(),
        release: os.release(),
      },
      process: {
        execArgv: process.execArgv,
        execPath: process.execPath,
        memoryUsage: process.memoryUsage(),
        pid: process.pid,
        platform: process.platform,
        uptime: process.uptime(),
      },
      uptime: process.uptime(),
      status: 'ok',
    }
  })

const createServer = (client, config) => {
  const PROD = config.nodeEnv === 'production'
  const app = express()

  if (PROD) {
    Raven.config(config.sentryDns).install()
    app.use(Raven.requestHandler())
  }

  app.use(expressWinston.logger({
    transports: [
      new winston.transports.Console({ colorize: true }),
    ],
    msg: 'HTTP {{req.method}} {{req.url}}',
    expressFormat: true,
    colorize: true,
  }))
  app.use(cors())
  app.use(helmet())
  app.use(hpp())
  app.use(compression())

  app.use(express.static(path.resolve(__dirname, '..', 'dist')))

  app.use('/ping', (req, res) => {
    return res.json(checkPostgres(client))
  })

  app.use('/s3', require('react-s3-uploader/s3router')({
    bucket: `${config.s3BucketName}`,
    uniquePrefix: false,
    ACL: 'public-read',
    s3Options: {
      accessKeyId: config.accessKeyId,
      secretKeyId: config.secretKeyId,
    },
  }))

  app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, '..', 'dist', 'index.html'))
  })

  app.use(expressWinston.errorLogger({
    transports: [
      new winston.transports.Console({ colorize: true }),
    ],
  }))

  if (PROD) { app.use(Raven.errorHandler()) }

  const server = http.createServer(app)

  // Heroku dynos automatically timeout after 30s. Set our
  // own timeout here to force sockets to close before that.
  // https://devcenter.heroku.com/articles/request-timeout
  if (config.timeout) {
    server.setTimeout(config.timeout, (socket) => {
      const message = `Timeout of ${config.timeout}ms exceeded`

      socket.end([
        'HTTP/1.1 503 Service Unavailable',
        `Date: ${(new Date).toGMTString()}`,  // eslint-disable-line
        'Content-Type: text/plain',
        `Content-Length: ${message.length}`,
        'Connection: close',
        '',
        message,
      ].join('\r\n'))
    })
  }

  return server
}

const startServer = (serverConfig) => {
  const config = { ...DefaultServerConfig, ...serverConfig }
  const emailEmitter = new EmailEmitter()
  const client = new pg.Client(config.databaseUrl)
  const server = createServer(client, config)

  createMemoriesListener(client, emailEmitter)

  emailEmitter.on('memory_created', ({ payload }) => {
    let EmailTemplate
    const p = JSON.parse(payload)
    const fileNameEmailTemplate = path.resolve(__dirname, 'static',
      'template-email-edicao-memoria.html')

    fs.readFile(fileNameEmailTemplate, 'utf8', (err, fileContent) => {
      if (err) throw err
      const data = fileContent.toString()
      EmailTemplate = _.template(data)

      const ses = new aws.SES({
        accessKeyId: config.accessKeyId,
        secretAccessKey: config.secretAccessKey,
        region: 'us-west-2',
      })
      const eparam = {
        Destination: {
          ToAddresses: [`${p.owner_first_name}<${p.owner_email}>`],
        },
        Message: {
          Body: {
            Html: {
              Data: EmailTemplate(p),
            },
            Text: {
              Data: `Olá ${data.owner_first_name}!

Sua homenagem criada no #VivoEmNos está pronta. Caso tenha visto algo que não goste, você pode editar copiando e colando no navegador o link abaixo.

https://vivosemnos.org/memory/edit?token=${data.token}

Saudações,
Equipe Vivo Em Nós

Este email foi enviado porque foi criada uma homenagem no site www.vivosemnos.org. Se não foi você, desconsidere esse e-mail.

Caso esse email te incomode, fique à vontade para enviar um email para notificacoes@vivosemnos.org e pedir o cancelamento.

Brazil - Rio De Janeiro, RJ - Botafogo - Rua Visconde Silva, 21 - 22271-043`,
            },
          },
          Subject: {
            Data: 'Sua homenagem ficou pronta, acesse!',
          },
        },
        Source: 'Vivos Em Nós <notificacoes@vivosemnos.org>',
        ReplyToAddresses: ['Vivos Em Nós <notificacoes@vivosemnos.org>'],
        ReturnPath: 'Vivos Em Nós <notificacoes@vivosemnos.org>',
      }

      ses.sendEmail(eparam, function (err, data) {
        if (err) {
          throw (err)
        } else {
          winston.info(data)
        }
      })
    })
  })

  server.listen(config.port, (err) => {
    if (err) throw err
    winston.info(`server ${config.id} listening on port ${config.port}`)
  })
}

if (require.main === module) {
  throng({
    start: id => startServer({ id }),
    workers: process.env.WEB_CONCURRENCY || 1,
    lifetime: Infinity,
  })
}

export default createServer
<commit_msg>Fix health endpoint to works async<commit_after>import 'newrelic'
import http from 'http'
import express from 'express'
import winston from 'winston'
import expressWinston from 'express-winston'
import cors from 'cors'
import compression from 'compression'
import helmet from 'helmet'
import hpp from 'hpp'
import throng from 'throng'
import Raven from 'raven'
import dotenv from 'dotenv'
import path from 'path'
import aws from 'aws-sdk'
import pg from 'pg'
import EventEmitter from 'events'
import _ from 'lodash'
import fs from 'fs'
import os from 'os'

dotenv.config({ path: path.resolve(__dirname, '..', '.env') })

const DefaultServerConfig = {
  nodeEnv: process.env.NODE_ENV,
  port: process.env.PORT,
  timeout: 28000,
  accessKeyId: process.env.AWS_ACCESS_KEY_ID || 'xxx',
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || 'yyy',
  schemaName: process.env.SCHEMA_NAME,
  databaseUrl: process.env.DATABASE_URL || 'postgres://postgres@localhost/vivos-em-nos-pwa',
  sentryDns: process.env.SENTRY_DSN,
  s3BucketName: process.env.AWS_BUCKET || 'vivo-em-nos-staging',
}

class EmailEmitter extends EventEmitter {}

const createMemoriesListener = (client, emailEmitter) =>
  () => {
    client.on('notification', (msg) => {
      emailEmitter.emit('memory_created', msg)
    })

    client.query('LISTEN new_memories')

    return client
    // client.end(function (err) {
    //   if (err) throw err
    // });
  }

// https://github.com/FastIT/health-check
const checkPostgres = (client, res) => {
  client.query('SELECT NOW() AS "the_time"', (err, resDb) => {
    if (!err) {
      res.json({ status: 'ko', online: false, error: err })
    }

    res.json({
      online: true,
      os: {
        arch: os.arch(),
        loadavg: os.loadavg(),
        freemem: os.freemem(),
        platform: os.platform(),
        totalmem: os.totalmem(),
        uptime: os.uptime(),
        release: os.release(),
      },
      process: {
        execArgv: process.execArgv,
        execPath: process.execPath,
        memoryUsage: process.memoryUsage(),
        pid: process.pid,
        platform: process.platform,
        uptime: process.uptime(),
      },
      uptime: process.uptime(),
      status: 'ok',
    })
  })
}

const createServer = (client, config) => {
  const PROD = config.nodeEnv === 'production'
  const app = express()

  if (PROD) {
    Raven.config(config.sentryDns).install()
    app.use(Raven.requestHandler())
  }

  app.use(expressWinston.logger({
    transports: [
      new winston.transports.Console({ colorize: true }),
    ],
    msg: 'HTTP {{req.method}} {{req.url}}',
    expressFormat: true,
    colorize: true,
  }))
  app.use(cors())
  app.use(helmet())
  app.use(hpp())
  app.use(compression())

  app.use(express.static(path.resolve(__dirname, '..', 'dist')))

  app.use('/ping', (req, res) => {
    checkPostgres(client, res)
  })

  app.use('/s3', require('react-s3-uploader/s3router')({
    bucket: `${config.s3BucketName}`,
    uniquePrefix: false,
    ACL: 'public-read',
    s3Options: {
      accessKeyId: config.accessKeyId,
      secretKeyId: config.secretKeyId,
    },
  }))

  app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, '..', 'dist', 'index.html'))
  })

  app.use(expressWinston.errorLogger({
    transports: [
      new winston.transports.Console({ colorize: true }),
    ],
  }))

  if (PROD) { app.use(Raven.errorHandler()) }

  const server = http.createServer(app)

  // Heroku dynos automatically timeout after 30s. Set our
  // own timeout here to force sockets to close before that.
  // https://devcenter.heroku.com/articles/request-timeout
  if (config.timeout) {
    server.setTimeout(config.timeout, (socket) => {
      const message = `Timeout of ${config.timeout}ms exceeded`

      socket.end([
        'HTTP/1.1 503 Service Unavailable',
        `Date: ${(new Date).toGMTString()}`,  // eslint-disable-line
        'Content-Type: text/plain',
        `Content-Length: ${message.length}`,
        'Connection: close',
        '',
        message,
      ].join('\r\n'))
    })
  }

  return server
}

const startServer = (serverConfig) => {
  const config = { ...DefaultServerConfig, ...serverConfig }
  const emailEmitter = new EmailEmitter()
  // const client = new pg.Client(config.databaseUrl)
  const pool = new pg.Pool(config);

  pool.on('error', function (err, client) {
    // if an error is encountered by a client while it sits idle in the pool
    // the pool itself will emit an error event with both the error and
    // the client which emitted the original error
    // this is a rare occurrence but can happen if there is a network partition
    // between your application and the database, the database restarts, etc.
    // and so you might want to handle it and at least log it out
    console.error('idle client error', err.message, err.stack);
  })

  // pool.connect((err) => {
  //   if (err) throw err

  const server = createServer(pool, config)

  createMemoriesListener(pool, emailEmitter)

  emailEmitter.on('memory_created', ({ payload }) => {
    let EmailTemplate
    const p = JSON.parse(payload)
    const fileNameEmailTemplate = path.resolve(__dirname, 'static',
      'template-email-edicao-memoria.html')

    fs.readFile(fileNameEmailTemplate, 'utf8', (err, fileContent) => {
      if (err) throw err
      const data = fileContent.toString()
      EmailTemplate = _.template(data)

      const ses = new aws.SES({
        accessKeyId: config.accessKeyId,
        secretAccessKey: config.secretAccessKey,
        region: 'us-west-2',
      })
      const eparam = {
        Destination: {
          ToAddresses: [`${p.owner_first_name}<${p.owner_email}>`],
        },
        Message: {
          Body: {
            Html: {
              Data: EmailTemplate(p),
            },
            Text: {
              Data: `Olá ${data.owner_first_name}!

Sua homenagem criada no #VivoEmNos está pronta. Caso tenha visto algo que não goste, você pode editar copiando e colando no navegador o link abaixo.

https://vivosemnos.org/memory/edit?token=${data.token}

Saudações,
Equipe Vivo Em Nós

Este email foi enviado porque foi criada uma homenagem no site www.vivosemnos.org. Se não foi você, desconsidere esse e-mail.

Caso esse email te incomode, fique à vontade para enviar um email para notificacoes@vivosemnos.org e pedir o cancelamento.

Brazil - Rio De Janeiro, RJ - Botafogo - Rua Visconde Silva, 21 - 22271-043`,
            },
          },
          Subject: {
            Data: 'Sua homenagem ficou pronta, acesse!',
          },
        },
        Source: 'Vivos Em Nós <notificacoes@vivosemnos.org>',
        ReplyToAddresses: ['Vivos Em Nós <notificacoes@vivosemnos.org>'],
        ReturnPath: 'Vivos Em Nós <notificacoes@vivosemnos.org>',
      }

      ses.sendEmail(eparam, function (err, data) {
        if (err) {
          throw (err)
        } else {
          winston.info(data)
        }
      })
    })
  })

  server.listen(config.port, (err) => {
    if (err) throw err
    winston.info(`server ${config.id} listening on port ${config.port}`)
  })
}

if (require.main === module) {
  throng({
    start: id => startServer({ id }),
    workers: process.env.WEB_CONCURRENCY || 1,
    lifetime: Infinity,
  })
}

export default createServer
<|endoftext|>


<commit_before>'use-strict'

var hookshot = require('hookshot'),
	fs         = require('fs'),
	exec       = require('child_process').exec,
	sh         = require('execSync'),
	request    = require('request'),
	colors     = require('colors'),
	nodemailer = require('nodemailer'),
	CronJob 	 = require('cron').CronJob,
	time 			 = require('time');

var config      = require('../config.json'),
		sh_commands = require('./sh-commands.js'),
		email_transporter,
		email_options;

var xoauth2_generator = require('xoauth2').createXOAuth2Generator({
	user: config.email.address,
	clientId: config.email.clientId,
	clientSecret: config.email.clientSecret,
	refreshToken: config.email.refreshToken
});

if (config.email.enabled){
	// Create reusable transporter object using SMTP transport
	email_transporter = nodemailer.createTransport({
			service: config.email.service,
			auth: {
				xoauth2: xoauth2_generator
			}
		});

	email_options = {
		from: config.email.name + ' <'+config.email.address+'>' ,
		subject: '[Kestrel] Status update'
	};
}

function sendEmail(context, mode, most_recent_commit, stdout){
	var committer,
			committer_email,
			committer_name,
			body_text,
			now,
			here_and_now, // A timezone'd version of `now`.
			msg,
			commit_messages_and_urls,
			commit_length_text,
			commit_calculated_length,
			s,
			mode_verb,
			info,
			most_recent_commit,
			deploy_statement,
			deploy_type,
			bucket_environment,
			local_path,
			remote_path,
			when_msg = '',
			s3_output = '';

	if (config.email.enabled) {
		if (mode == 'deploy'){
			mode_verb = 'performed';
		} else if (mode == 'schedule') {
			mode_verb = 'scheduled';
		}

		info = context.info;
		most_recent_commit = context.most_recent_commit;
		deploy_statement = context.deploy_statement;
		deploy_type = context.deploy_type;
		bucket_environment = context.bucket_environment;
		local_path = context.local_path;
		remote_path = context.remote_path;
		when = context.when;

		committer = most_recent_commit.committer;
		committer_email = committer.email;
		committer_name  = committer.name;

		now = new time.Date();
		here_and_now = now.setTimezone(config.timezone).toString();

		commit_length_text = '.';
		commit_calculated_length = info.commits.length - 1;
		s = 's';

		// Make a string saying how many commits we have, minus the staging commit
		if (commit_calculated_length != 0){
			// Make sure we get our plurals correct.
			if (commit_calculated_length == 1) {
				s = '';
			}
			commit_length_text = ' containing ' +commit_calculated_length+' commit'+s+':

';
		}
		// Concatenate a string of urls for each of these commits along with the commit message
		// Reverse to put them in rever-cron order
		commit_messages_and_urls = info.commits.map(function(cmt){ return cmt.url + ' "' + cmt.message + '"'; }).reverse().slice(1,info.commits.length).join('
');

		// In schedule mode there is no s3 output so it stays as an empty string
		if (mode == 'deploy'){
			s3_output = '

';
			if (!stdout.trim()){
				s3_output += 'S3 said everything was already up-to-date! If you\'ve removed files from your project and want to have that deletion reflected on S3 (possible if you\'ve renamed files, for instance) try doing a hard deploy.';
			} else {
				s3_output += 'Here\'s what S3 is telling me it did:
';
				s3_output += stdout.replace(/remaining/g, 'remaining
');
			}
		} else if (mode == 'schedule'){
			when_msg = ' scheduled for ' + when + '';
		}

		// What's the main body message look like?
		msg = 'I just '+mode_verb+' a '+deploy_type+' deploy to S3 *'+bucket_environment+'*'+when_msg+commit_length_text+commit_messages_and_urls+'

I put the the local folder of `' + local_path + '`
onto S3 as `' + remote_path + '`'+s3_output;

		// Assemble an html version
		body_text = 'Hi '+ committer_name+',

' + msg + '

'+'Talk to you later,

Kestrel Songs ('+here_and_now+')';
		email_options.html = body_text;

		// And a plain-text version
		email_options.text = body_text.replace(/
/g, '\n')
																	.replace(/<(\/?)strong>/g, '*');

		// Fill out the rest of the information and send
		email_options.to = committer_email;
		email_transporter.sendMail(email_options, function(error, info){
			if(error){
				console.log('Error in email sending'.red, error);
			}else{
				console.log('Email success! To: '.green + committer_name + ' <' + committer_email + '>');
			}
		});
	}
}

function verifyAccount(incoming_repo){
	if (incoming_repo == config.github_listener.account_name) return true;
	return false;
}
function checkIfCommitterIsDeployer(members, committer){
	return members.some(function(member){
		return member.login === committer;
	});
}
function verifyCommitter(last_commit, cb){
	// You only need to verify the deployer if you're using teams, otherwise disable it and always allow anyone pushing to that repo to deploy.
	if (!config.verify_committer.enabled){
		cb(true);
	}else{
		var committer = last_commit.committer.username;
		request({
			url: 'https://api.github.com/teams/' + config.verify_committer.team_id + '/members?access_token=' + config.verify_committer.access_token,
			headers: {
        'User-Agent': 'Kestrel-publisher'
    		}
    	}, function (error, response, body) {
		  if (!error) {
		  	var committer_is_deployer = checkIfCommitterIsDeployer(JSON.parse(body), committer);
		    cb(committer_is_deployer);
		  } else {
		  	console.log('Error verifying committer'.red, JSON.stringify(error))
		  }
		})
	}
}

function createDirGitInit(info){
	console.log('Creating folder and git repository...'.yellow);
	var repo_name = info.repository.name;

	fs.mkdirSync('./repositories/' + repo_name);

	var remote_url_arr = info.repository.url.split('//');
	var authenticated_remote_url = remote_url_arr[0] + '//' + config.verify_committer.access_token + '@' + remote_url_arr[1];
	var create_statement = sh_commands.createGitRepoAndRemotes(repo_name, authenticated_remote_url);
	console.log(create_statement);
  sh.run(create_statement);
	console.log('Git created!'.green);
}
function pullLatest(info){
	var repo_name = info.repository.name,
			branch_name = info.ref.split('/')[2], // `ref: "refs/heads/<branchname>` => `branchname`
			delete_branch;

	if (!fs.existsSync('./repositories/' + repo_name)){
		createDirGitInit(info);
	}

	// Download latest data
	var fetch_statement = sh_commands.fetchLatest(repo_name);
	sh.run(fetch_statement);

	// If it's deleted, delete it!
	if (info.deleted) {
		delete_branch = sh_commands.deleteBranch(repo_name, branch_name);
		sh.run(delete_branch);
	}

	// Update all branches
	var track_all_branches = sh_commands.trackAllBranches(repo_name);
	sh.run(track_all_branches);

	// Put the working tree back on to master
	var checkout_master = sh_commands.checkoutMaster(repo_name);
	sh.run(checkout_master);
}
function checkForDeployMsg(last_commit){
	console.log('Checking if deploy message in...'.yellow, last_commit.message);
	var commit_trigger = last_commit.message.split('::')[1], // 'bucket_environment::trigger::local_path::remote_path::when' -> "trigger"
	    cp_deploy_regx   = new RegExp(config.s3.hard_deploy.trigger),
	    sync_deploy_regx = new RegExp(config.s3.sync_deploy_trigger);

	if (config.s3.hard_deploy.enabled && cp_deploy_regx.exec(commit_trigger)) return 'hard';
	if (sync_deploy_regx.exec(commit_trigger)) return 'sync';
	return false;
}

function deployToS3(){
	var that = this;
	var deploy_statement = this.deploy_statement;

	console.log('Attempting to deploy with'.yellow, deploy_statement);
	exec(deploy_statement, function(error, stdout){
		// Log deployment result
		console.log('Deployed!'.green);
		console.log(stdout);
		sendEmail(that, 'deploy', most_recent_commit, stdout);
	});

}
function prepS3Deploy(deploy_type, info, most_recent_commit){
	var repo_name   = info.repository.name,
			last_commit_msg = most_recent_commit.message,
			commit_parts = last_commit_msg.split('::'), // 'bucket_environment::trigger::local_path::remote_path' -> [bucket_environment, trigger, local_path, remote_path], e.g. `staging::sync-flamingo::kestrel-test::2014/kestrel-cli`
			bucket_environment  = commit_parts[0], // Either `prod` or `staging`
			local_path  = commit_parts[2], // Either `repo_name` or `repo_name/sub-directory`
	    remote_path = commit_parts[3], // The folder we'll be writing into. An enclosing folder and the repo name plus any sub-directory, e.g. `2014/kestrel-test` or `2014/kestrel-test/output`
			when = commit_parts[4], // Date/time string in YYYY-MM-DDTHH:MM format
			job;

	var deploy_statement = sh_commands.deploy(deploy_type, config.s3.buckets[bucket_environment], local_path, remote_path, config.s3.exclude);
	// These are the variables packaged up so they can be accessed by `deployToS3`
	// We can't really pass them super easily since `CronJob` wants a function by reference
	var context = {
		info: info,
		most_recent_commit: most_recent_commit,
		deploy_type: deploy_type,
		bucket_environment: bucket_environment,
		local_path: local_path,
		remote_path: remote_path,
		deploy_statement: deploy_statement,
		when: when
	};
	if (when == 'now'){
		deployToS3.call(context);
	} else {
		job = new CronJob({
			cronTime: new Date(when),
			onTick: deployToS3,
			start: true,
			timeZone: config.timezone,
			context: context
		});
		sendEmail(context, 'schedule', most_recent_commit);
	}

}

hookshot(function(info){
	// Is this request coming from the specified GitHub Account?
	var is_account_verified = verifyAccount(info.repository.owner.name);
	// Is there a deploy message present?
	var most_recent_commit,
			deploy_status;
	// The last commit in the array is the most recent
	// But `info.commits` will be an empty array if you pushed a new branch with no commits
	if (info.commits.length) {
		most_recent_commit  = info.commits[info.commits.length - 1];
		deploy_status       = checkForDeployMsg(most_recent_commit);
		console.log('Deploy status is'.cyan, deploy_status);
	}
	// Is this coming from the whitelisted GitHub account?
	if (is_account_verified){
		pullLatest(info);
		// if (config.email.enabled){
		// 	sendEmail(most_recent_commit, 'Pulled down '+info.commits.length+' commits. The most recent was made at ' + most_recent_commit.timestamp + ': '+ most_recent_commit.url);
		// }

		// Are we deploying? Has that option been enabled and does the commit have the appropriate message?
		if (config.s3.enabled && deploy_status){
			verifyCommitter(most_recent_commit, function(committer_approved){

				// Does the committer have deploy? privileges?
				if (committer_approved) {
					prepS3Deploy(deploy_status, info, most_recent_commit);
				} else {
					console.log('Unapproved committer attempted deployment.'.red)
				}

			});
		}
	}
}).listen(config.github_listener.port);

console.log('Listening on port... ' + config.github_listener.port);	<commit_msg>more comment updates<commit_after>'use-strict'

var hookshot = require('hookshot'),
	fs         = require('fs'),
	exec       = require('child_process').exec,
	sh         = require('execSync'),
	request    = require('request'),
	colors     = require('colors'),
	nodemailer = require('nodemailer'),
	CronJob 	 = require('cron').CronJob,
	time 			 = require('time');

var config      = require('../config.json'),
		sh_commands = require('./sh-commands.js'),
		email_transporter,
		email_options;

var xoauth2_generator = require('xoauth2').createXOAuth2Generator({
	user: config.email.address,
	clientId: config.email.clientId,
	clientSecret: config.email.clientSecret,
	refreshToken: config.email.refreshToken
});

if (config.email.enabled){
	// Create reusable transporter object using SMTP transport
	email_transporter = nodemailer.createTransport({
			service: config.email.service,
			auth: {
				xoauth2: xoauth2_generator
			}
		});

	email_options = {
		from: config.email.name + ' <'+config.email.address+'>' ,
		subject: '[Kestrel] Status update'
	};
}

function sendEmail(context, mode, most_recent_commit, stdout){
	var committer,
			committer_email,
			committer_name,
			body_text,
			now,
			here_and_now, // A timezone'd version of `now`.
			msg,
			commit_messages_and_urls,
			commit_length_text,
			commit_calculated_length,
			s,
			mode_verb,
			info,
			most_recent_commit,
			deploy_statement,
			deploy_type,
			bucket_environment,
			local_path,
			remote_path,
			when_msg = '',
			s3_output = '';

	if (config.email.enabled) {
		if (mode == 'deploy'){
			mode_verb = 'performed';
		} else if (mode == 'schedule') {
			mode_verb = 'scheduled';
		}

		info = context.info;
		most_recent_commit = context.most_recent_commit;
		deploy_statement = context.deploy_statement;
		deploy_type = context.deploy_type;
		bucket_environment = context.bucket_environment;
		local_path = context.local_path;
		remote_path = context.remote_path;
		when = context.when;

		committer = most_recent_commit.committer;
		committer_email = committer.email;
		committer_name  = committer.name;

		now = new time.Date();
		here_and_now = now.setTimezone(config.timezone).toString();

		commit_length_text = '.';
		commit_calculated_length = info.commits.length - 1;
		s = 's';

		// Make a string saying how many commits we have, minus the staging commit
		if (commit_calculated_length != 0){
			// Make sure we get our plurals correct.
			if (commit_calculated_length == 1) {
				s = '';
			}
			commit_length_text = ' containing ' +commit_calculated_length+' commit'+s+':

';
		}
		// Concatenate a string of urls for each of these commits along with the commit message
		// Reverse to put them in rever-cron order
		commit_messages_and_urls = info.commits.map(function(cmt){ return cmt.url + ' "' + cmt.message + '"'; }).reverse().slice(1,info.commits.length).join('
');

		// In schedule mode there is no s3 output so it stays as an empty string
		if (mode == 'deploy'){
			s3_output = '

';
			if (!stdout.trim()){
				s3_output += 'S3 said everything was already up-to-date! If you\'ve removed files from your project and want to have that deletion reflected on S3 (possible if you\'ve renamed files, for instance) try doing a hard deploy.';
			} else {
				s3_output += 'Here\'s what S3 is telling me it did:
';
				s3_output += stdout.replace(/remaining/g, 'remaining
');
			}
		} else if (mode == 'schedule'){
			when_msg = ' scheduled for ' + when + '';
		}

		// What's the main body message look like?
		msg = 'I just '+mode_verb+' a '+deploy_type+' deploy to S3 *'+bucket_environment+'*'+when_msg+commit_length_text+commit_messages_and_urls+'

I put the the local folder of `' + local_path + '`
onto S3 as `' + remote_path + '`'+s3_output;

		// Assemble an html version
		body_text = 'Hi '+ committer_name+',

' + msg + '

'+'Talk to you later,

Kestrel Songs ('+here_and_now+')';
		email_options.html = body_text;

		// And a plain-text version
		email_options.text = body_text.replace(/
/g, '\n')
																	.replace(/<(\/?)strong>/g, '*');

		// Fill out the rest of the information and send
		email_options.to = committer_email;
		email_transporter.sendMail(email_options, function(error, info){
			if(error){
				console.log('Error in email sending'.red, error);
			}else{
				console.log('Email success! To: '.green + committer_name + ' <' + committer_email + '>');
			}
		});
	}
}

function verifyAccount(incoming_repo){
	if (incoming_repo == config.github_listener.account_name) return true;
	return false;
}
function checkIfCommitterIsDeployer(members, committer){
	return members.some(function(member){
		return member.login === committer;
	});
}
function verifyCommitter(last_commit, cb){
	// You only need to verify the deployer if you're using teams, otherwise disable it and always allow anyone pushing to that repo to deploy.
	if (!config.verify_committer.enabled){
		cb(true);
	}else{
		var committer = last_commit.committer.username;
		request({
			url: 'https://api.github.com/teams/' + config.verify_committer.team_id + '/members?access_token=' + config.verify_committer.access_token,
			headers: {
        'User-Agent': 'Kestrel-publisher'
    		}
    	}, function (error, response, body) {
		  if (!error) {
		  	var committer_is_deployer = checkIfCommitterIsDeployer(JSON.parse(body), committer);
		    cb(committer_is_deployer);
		  } else {
		  	console.log('Error verifying committer'.red, JSON.stringify(error))
		  }
		})
	}
}

function createDirGitInit(info){
	console.log('Creating folder and git repository...'.yellow);
	var repo_name = info.repository.name;

	fs.mkdirSync('./repositories/' + repo_name);

	var remote_url_arr = info.repository.url.split('//');
	var authenticated_remote_url = remote_url_arr[0] + '//' + config.verify_committer.access_token + '@' + remote_url_arr[1];
	var create_statement = sh_commands.createGitRepoAndRemotes(repo_name, authenticated_remote_url);
	console.log(create_statement);
  sh.run(create_statement);
	console.log('Git created!'.green);
}
function pullLatest(info){
	var repo_name = info.repository.name,
			branch_name = info.ref.split('/')[2], // `ref: "refs/heads/<branchname>` => `branchname`
			delete_branch;

	if (!fs.existsSync('./repositories/' + repo_name)){
		createDirGitInit(info);
	}

	// Download latest data
	var fetch_statement = sh_commands.fetchLatest(repo_name);
	sh.run(fetch_statement);

	// If it's deleted, delete it!
	if (info.deleted) {
		delete_branch = sh_commands.deleteBranch(repo_name, branch_name);
		sh.run(delete_branch);
	}

	// Update all branches
	var track_all_branches = sh_commands.trackAllBranches(repo_name);
	sh.run(track_all_branches);

	// Put the working tree back on to master
	var checkout_master = sh_commands.checkoutMaster(repo_name);
	sh.run(checkout_master);
}
function checkForDeployMsg(last_commit){
	console.log('Checking if deploy message in...'.yellow, last_commit.message);
	var commit_trigger = last_commit.message.split('::')[1], // 'bucket_environment::trigger::local_path::remote_path::when' -> "trigger"
	    cp_deploy_regx   = new RegExp(config.s3.hard_deploy.trigger),
	    sync_deploy_regx = new RegExp(config.s3.sync_deploy_trigger);

	if (config.s3.hard_deploy.enabled && cp_deploy_regx.exec(commit_trigger)) return 'hard';
	if (sync_deploy_regx.exec(commit_trigger)) return 'sync';
	return false;
}

function deployToS3(){
	var that = this;
	var deploy_statement = this.deploy_statement;

	console.log('Attempting to deploy with'.yellow, deploy_statement);
	exec(deploy_statement, function(error, stdout){
		// Log deployment result
		console.log('Deployed!'.green);
		console.log(stdout);
		sendEmail(that, 'deploy', most_recent_commit, stdout);
	});

}
function prepS3Deploy(deploy_type, info, most_recent_commit){
	var repo_name   = info.repository.name,
			last_commit_msg = most_recent_commit.message,
			commit_parts = last_commit_msg.split('::'), // 'bucket_environment::trigger::local_path::remote_path::when' -> [bucket_environment, trigger, local_path, remote_path], e.g. `staging::sync-flamingo::kestrel-test::2014/kestrel-cli:2014-11-11T14:02`
			bucket_environment  = commit_parts[0], // Either `prod` or `staging`
			local_path  = commit_parts[2], // Either `repo_name` or `repo_name/sub-directory`
	    remote_path = commit_parts[3], // The folder we'll be writing into. An enclosing folder and the repo name plus any sub-directory, e.g. `2014/kestrel-test` or `2014/kestrel-test/output`
			when = commit_parts[4], // Date/time string in YYYY-MM-DDTHH:MM format
			job;

	var deploy_statement = sh_commands.deploy(deploy_type, config.s3.buckets[bucket_environment], local_path, remote_path, config.s3.exclude);
	// These are the variables packaged up so they can be accessed by `deployToS3`
	// We can't really pass them super easily since `CronJob` wants a function by reference
	var context = {
		info: info,
		most_recent_commit: most_recent_commit,
		deploy_type: deploy_type,
		bucket_environment: bucket_environment,
		local_path: local_path,
		remote_path: remote_path,
		deploy_statement: deploy_statement,
		when: when
	};
	if (when == 'now'){
		deployToS3.call(context);
	} else {
		job = new CronJob({
			cronTime: new Date(when),
			onTick: deployToS3,
			start: true,
			timeZone: config.timezone,
			context: context
		});
		sendEmail(context, 'schedule', most_recent_commit);
	}

}

hookshot(function(info){
	// Is this request coming from the specified GitHub Account?
	var is_account_verified = verifyAccount(info.repository.owner.name);
	// Is there a deploy message present?
	var most_recent_commit,
			deploy_status;
	// The last commit in the array is the most recent
	// But `info.commits` will be an empty array if you pushed a new branch with no commits
	if (info.commits.length) {
		most_recent_commit  = info.commits[info.commits.length - 1];
		deploy_status       = checkForDeployMsg(most_recent_commit);
		console.log('Deploy status is'.cyan, deploy_status);
	}
	// Is this coming from the whitelisted GitHub account?
	if (is_account_verified){
		pullLatest(info);
		// if (config.email.enabled){
		// 	sendEmail(most_recent_commit, 'Pulled down '+info.commits.length+' commits. The most recent was made at ' + most_recent_commit.timestamp + ': '+ most_recent_commit.url);
		// }

		// Are we deploying? Has that option been enabled and does the commit have the appropriate message?
		if (config.s3.enabled && deploy_status){
			verifyCommitter(most_recent_commit, function(committer_approved){

				// Does the committer have deploy? privileges?
				if (committer_approved) {
					prepS3Deploy(deploy_status, info, most_recent_commit);
				} else {
					console.log('Unapproved committer attempted deployment.'.red)
				}

			});
		}
	}
}).listen(config.github_listener.port);

console.log('Listening on port... ' + config.github_listener.port);	<|endoftext|>


<commit_before>'use-strict'

var hookshot = require('hookshot'),
	fs         = require('fs'),
	exec       = require('child_process').exec,
	sh         = require('execSync'),
	request    = require('request'),
	colors     = require('colors'),
	nodemailer = require('nodemailer');

var config      = require('../config.json'),
		sh_commands = require('./sh-commands.js'),
		email_transporter,
		email_options;

var xoauth2_generator = require('xoauth2').createXOAuth2Generator({
	user: config.email.address,
	clientId: config.email.clientId,
	clientSecret: config.email.clientSecret,
	refreshToken: config.email.refreshToken
});

if (config.email.enabled){
	// Create reusable transporter object using SMTP transport
	email_transporter = nodemailer.createTransport({
			service: config.email.service,
			auth: {
				xoauth2: xoauth2_generator
			}
		});

	email_options = {
		from: config.email.name + ' <'+config.email.address+'>' ,
		subject: '[Kestrel] Status update'
	};
}

function sendEmail(most_recent_commit, msg){
	var committer = most_recent_commit.committer;
	var committer_email = committer.email,
			committer_name  = committer.name;

	email_options.to = committer_email;
	email_options.html = 'Hi '+ committer_name+',

' + msg + '

'+'Talk to you later,

Kestrel Songs';
	email_options.html = email_options.html.replace(/\n/g, '
');
	email_options.text = 'Hi '+ committer_name+',\n\n' + msg + '\n\n\n'+'Talk to you later,\n\nKestrel Songs ('+new Date().toISOString()+')';
	email_transporter.sendMail(email_options, function(error, info){
		if(error){
			console.log('Error in email sending'.red, error);
		}else{
			console.log('Email success! To: '.green + committer_name + ' <' + committer_email + '>');
		}
	});
}

function verifyAccount(incoming_repo){
	if (incoming_repo == config.github_listener.account_name) return true;
	return false;
}
function checkIfCommitterIsDeployer(members, committer){
	return members.some(function(member){
		return member.login === committer;
	});
}
function verifyCommitter(last_commit, cb){
	// You only need to verify the deployer if you're using teams, otherwise disable it and always allow anyone pushing to that repo to deploy.
	if (!config.verify_committer.enabled){
		cb(true);
	}else{
		var committer = last_commit.committer.username;
		request({
			url: 'https://api.github.com/teams/' + config.verify_committer.team_id + '/members?access_token=' + config.verify_committer.access_token,
			headers: {
        'User-Agent': 'Kestrel-publisher'
    		}
    	}, function (error, response, body) {
		  if (!error) {
		  	var committer_is_deployer = checkIfCommitterIsDeployer(JSON.parse(body), committer);
		    cb(committer_is_deployer);
		  } else {
		  	console.log('Error verifying committer'.red, JSON.stringify(error))
		  }
		})
	}
}

function createDirGitInit(info){
	console.log('Creating folder and git repository...'.yellow);
	var repo_name = info.repository.name;

	fs.mkdirSync('./repositories/' + repo_name);

	var remote_url_arr = info.repository.url.split('//');
	var authenticated_remote_url = remote_url_arr[0] + '//' + config.verify_committer.access_token + '@' + remote_url_arr[1];
	var create_statement = sh_commands.createGitRepoAndRemotes(repo_name, authenticated_remote_url);
	console.log(create_statement);
  sh.run(create_statement);
	console.log('Git created!'.green);
}
function pullLatest(info){
	var repo_name = info.repository.name,
			branch_name = info.ref.split('/')[2], // `ref: "refs/heads/<branchname>` => `branchname`
			delete_branch;

	if (!fs.existsSync('./repositories/' + repo_name)){
		createDirGitInit(info);
	}

	// Download latest data
	var fetch_statement = sh_commands.fetchLatest(repo_name);
	sh.run(fetch_statement);

	// If it's deleted, delete it!
	if (info.deleted) {
		delete_branch = sh_commands.deleteBranch(repo_name, branch_name);
		sh.run(delete_branch);
	}

	// Update all branches
	var track_all_branches = sh_commands.trackAllBranches(repo_name);
	sh.run(track_all_branches);

	// Put the working tree back on to master
	var checkout_master = sh_commands.checkoutMaster(repo_name);
	sh.run(checkout_master);
}
function checkForDeployMsg(last_commit){
	console.log('Checking if deploy message in...'.yellow, last_commit.message);
	var commit_trigger = last_commit.message.split('::')[1], // 'bucket_environment::trigger::local_path::remote_path' -> "trigger"
	    cp_deploy_regx   = new RegExp(config.s3.hard_deploy.trigger),
	    sync_deploy_regx = new RegExp(config.s3.sync_deploy_trigger);

	if (config.s3.hard_deploy.enabled && cp_deploy_regx.exec(commit_trigger)) return 'hard';
	if (sync_deploy_regx.exec(commit_trigger)) return 'sync';
	return false;
}
function deployToS3(deploy_type, info, most_recent_commit){
	var repo_name   = info.repository.name,
			last_commit_msg = most_recent_commit.message,
			commit_parts = last_commit_msg.split('::'), // 'bucket_environment::trigger::local_path::remote_path' -> [bucket_environment, trigger, local_path, remote_path], e.g. `staging::sync-flamingo::kestrel-test::2014/kestrel-cli`
			bucket_environment  = commit_parts[0], // Either `prod` or `staging`
			local_path  = commit_parts[2], // Either `repo_name` or `repo_name/sub-directory`
	    remote_path = commit_parts[3], // The folder we'll be writing into. An enclosing folder and the repo name plus any sub-directory, e.g. `2014/kestrel-test` or `2014/kestrel-test/output`
	    s = 's';

	if (info.commits.length == 1){
		s = '';
	}

	var deploy_statement = sh_commands.deploy(deploy_type, config.s3.buckets[bucket_environment], local_path, remote_path, config.s3.exclude);
	console.log('Attempting to deploy with'.yellow, deploy_statement);
	exec(deploy_statement, function(error, stdout){
		// Log deployment result
		console.log('Deployed!'.green, stdout);
		if (config.email.enabled) {
			sendEmail(most_recent_commit, 'I just performed a '+deploy_type+' deploy to S3 *'+bucket_environment+'* containing '+ info.commits.length + ' commit'+s+':\n\n'+info.commits.map(function(commit){ return commit.url; }).join('\n')+'\n\nI put the the local folder of `' + local_path + '`\n\nOnto S3 as `' + remote_path + '`\n\n\nHere\'s some more output:\n'+stdout);
		}
	});
}

hookshot(function(info){
	// Is this request coming from the specified GitHub Account?
	var is_account_verified = verifyAccount(info.repository.owner.name);
	// Is there a deploy message present?
	var most_recent_commit,
			deploy_status;
	// The last commit in the array is the most recent
	// But `info.commits` will be an empty array if you pushed a new branch with no commits
	if (info.commits.length) {
		most_recent_commit  = info.commits[info.commits.length - 1];
		deploy_status       = checkForDeployMsg(most_recent_commit);
		console.log('Deploy status is'.cyan, deploy_status);
	}
	// Is this coming from the whitelisted GitHub account?
	if (is_account_verified){
		pullLatest(info);
		// if (config.email.enabled){
		// 	sendEmail(most_recent_commit, 'Pulled down '+info.commits.length+' commits. The most recent was made at ' + most_recent_commit.timestamp + ': '+ most_recent_commit.url);
		// }

		// Are we deploying? Has that option been enabled and does the commit have the appropriate message?
		if (config.s3.enabled && deploy_status){
			verifyCommitter(most_recent_commit, function(committer_approved){

				// Does the committer have deploy? privileges?
				if (committer_approved) {
					deployToS3(deploy_status, info, most_recent_commit);
				} else {
					console.log('Unapproved committer attempted deployment.'.red)
				}

			});
		}
	}
}).listen(config.github_listener.port);

console.log('Listening on port... ' + config.github_listener.port);	<commit_msg>email s3 log formatting<commit_after>'use-strict'

var hookshot = require('hookshot'),
	fs         = require('fs'),
	exec       = require('child_process').exec,
	sh         = require('execSync'),
	request    = require('request'),
	colors     = require('colors'),
	nodemailer = require('nodemailer');

var config      = require('../config.json'),
		sh_commands = require('./sh-commands.js'),
		email_transporter,
		email_options;

var xoauth2_generator = require('xoauth2').createXOAuth2Generator({
	user: config.email.address,
	clientId: config.email.clientId,
	clientSecret: config.email.clientSecret,
	refreshToken: config.email.refreshToken
});

if (config.email.enabled){
	// Create reusable transporter object using SMTP transport
	email_transporter = nodemailer.createTransport({
			service: config.email.service,
			auth: {
				xoauth2: xoauth2_generator
			}
		});

	email_options = {
		from: config.email.name + ' <'+config.email.address+'>' ,
		subject: '[Kestrel] Status update'
	};
}

function sendEmail(most_recent_commit, msg){
	var committer = most_recent_commit.committer;
	var committer_email = committer.email,
			committer_name  = committer.name;

	email_options.to = committer_email;
	email_options.html = 'Hi '+ committer_name+',

' + msg + '

'+'Talk to you later,

Kestrel Songs';
	email_options.html = email_options.html.replace(/\n/g, '
');
	email_options.text = 'Hi '+ committer_name+',\n\n' + msg + '\n\n\n'+'Talk to you later,\n\nKestrel Songs ('+new Date().toISOString()+')';
	email_transporter.sendMail(email_options, function(error, info){
		if(error){
			console.log('Error in email sending'.red, error);
		}else{
			console.log('Email success! To: '.green + committer_name + ' <' + committer_email + '>');
		}
	});
}

function verifyAccount(incoming_repo){
	if (incoming_repo == config.github_listener.account_name) return true;
	return false;
}
function checkIfCommitterIsDeployer(members, committer){
	return members.some(function(member){
		return member.login === committer;
	});
}
function verifyCommitter(last_commit, cb){
	// You only need to verify the deployer if you're using teams, otherwise disable it and always allow anyone pushing to that repo to deploy.
	if (!config.verify_committer.enabled){
		cb(true);
	}else{
		var committer = last_commit.committer.username;
		request({
			url: 'https://api.github.com/teams/' + config.verify_committer.team_id + '/members?access_token=' + config.verify_committer.access_token,
			headers: {
        'User-Agent': 'Kestrel-publisher'
    		}
    	}, function (error, response, body) {
		  if (!error) {
		  	var committer_is_deployer = checkIfCommitterIsDeployer(JSON.parse(body), committer);
		    cb(committer_is_deployer);
		  } else {
		  	console.log('Error verifying committer'.red, JSON.stringify(error))
		  }
		})
	}
}

function createDirGitInit(info){
	console.log('Creating folder and git repository...'.yellow);
	var repo_name = info.repository.name;

	fs.mkdirSync('./repositories/' + repo_name);

	var remote_url_arr = info.repository.url.split('//');
	var authenticated_remote_url = remote_url_arr[0] + '//' + config.verify_committer.access_token + '@' + remote_url_arr[1];
	var create_statement = sh_commands.createGitRepoAndRemotes(repo_name, authenticated_remote_url);
	console.log(create_statement);
  sh.run(create_statement);
	console.log('Git created!'.green);
}
function pullLatest(info){
	var repo_name = info.repository.name,
			branch_name = info.ref.split('/')[2], // `ref: "refs/heads/<branchname>` => `branchname`
			delete_branch;

	if (!fs.existsSync('./repositories/' + repo_name)){
		createDirGitInit(info);
	}

	// Download latest data
	var fetch_statement = sh_commands.fetchLatest(repo_name);
	sh.run(fetch_statement);

	// If it's deleted, delete it!
	if (info.deleted) {
		delete_branch = sh_commands.deleteBranch(repo_name, branch_name);
		sh.run(delete_branch);
	}

	// Update all branches
	var track_all_branches = sh_commands.trackAllBranches(repo_name);
	sh.run(track_all_branches);

	// Put the working tree back on to master
	var checkout_master = sh_commands.checkoutMaster(repo_name);
	sh.run(checkout_master);
}
function checkForDeployMsg(last_commit){
	console.log('Checking if deploy message in...'.yellow, last_commit.message);
	var commit_trigger = last_commit.message.split('::')[1], // 'bucket_environment::trigger::local_path::remote_path' -> "trigger"
	    cp_deploy_regx   = new RegExp(config.s3.hard_deploy.trigger),
	    sync_deploy_regx = new RegExp(config.s3.sync_deploy_trigger);

	if (config.s3.hard_deploy.enabled && cp_deploy_regx.exec(commit_trigger)) return 'hard';
	if (sync_deploy_regx.exec(commit_trigger)) return 'sync';
	return false;
}
function deployToS3(deploy_type, info, most_recent_commit){
	var repo_name   = info.repository.name,
			last_commit_msg = most_recent_commit.message,
			commit_parts = last_commit_msg.split('::'), // 'bucket_environment::trigger::local_path::remote_path' -> [bucket_environment, trigger, local_path, remote_path], e.g. `staging::sync-flamingo::kestrel-test::2014/kestrel-cli`
			bucket_environment  = commit_parts[0], // Either `prod` or `staging`
			local_path  = commit_parts[2], // Either `repo_name` or `repo_name/sub-directory`
	    remote_path = commit_parts[3], // The folder we'll be writing into. An enclosing folder and the repo name plus any sub-directory, e.g. `2014/kestrel-test` or `2014/kestrel-test/output`
	    s = 's';

	if (info.commits.length == 1){
		s = '';
	}

	var deploy_statement = sh_commands.deploy(deploy_type, config.s3.buckets[bucket_environment], local_path, remote_path, config.s3.exclude);
	console.log('Attempting to deploy with'.yellow, deploy_statement);
	exec(deploy_statement, function(error, stdout){
		// Log deployment result
		console.log('Deployed!'.green)
		console.log(stdout);
		if (config.email.enabled) {
			sendEmail(most_recent_commit, 'I just performed a '+deploy_type+' deploy to S3 *'+bucket_environment+'* containing '+ info.commits.length + ' commit'+s+':\n\n'+info.commits.map(function(commit){ return commit.url; }).join('\n')+'\n\nI put the the local folder of `' + local_path + '`\n\nOnto S3 as `' + remote_path + '`\n\n\nHere\'s some more output:\n'+stdout.replace(/remaining/g,'remaining\n'));
		}
	});
}

hookshot(function(info){
	// Is this request coming from the specified GitHub Account?
	var is_account_verified = verifyAccount(info.repository.owner.name);
	// Is there a deploy message present?
	var most_recent_commit,
			deploy_status;
	// The last commit in the array is the most recent
	// But `info.commits` will be an empty array if you pushed a new branch with no commits
	if (info.commits.length) {
		most_recent_commit  = info.commits[info.commits.length - 1];
		deploy_status       = checkForDeployMsg(most_recent_commit);
		console.log('Deploy status is'.cyan, deploy_status);
	}
	// Is this coming from the whitelisted GitHub account?
	if (is_account_verified){
		pullLatest(info);
		// if (config.email.enabled){
		// 	sendEmail(most_recent_commit, 'Pulled down '+info.commits.length+' commits. The most recent was made at ' + most_recent_commit.timestamp + ': '+ most_recent_commit.url);
		// }

		// Are we deploying? Has that option been enabled and does the commit have the appropriate message?
		if (config.s3.enabled && deploy_status){
			verifyCommitter(most_recent_commit, function(committer_approved){

				// Does the committer have deploy? privileges?
				if (committer_approved) {
					deployToS3(deploy_status, info, most_recent_commit);
				} else {
					console.log('Unapproved committer attempted deployment.'.red)
				}

			});
		}
	}
}).listen(config.github_listener.port);

console.log('Listening on port... ' + config.github_listener.port);	<|endoftext|>


<commit_before>import Express from 'express';
import config from './config';
import favicon from 'serve-favicon';
import compression from 'compression';
import path from 'path';
import PrettyError from 'pretty-error';
import http from 'http';
import httpProxy from 'http-proxy';
import session from 'client-sessions';
import bodyParser from 'body-parser'

import routes from './serverRoutes.map'

const targetUrl = process.env.API_URL;
const pretty = new PrettyError();
const app = new Express();
const server = new http.Server(app);
const proxy = httpProxy.createProxyServer({
  target: targetUrl
});

import request from 'superagent';

/*if (process.env.ENV === 'prod') {
  app.use((req, res, next) => {
    if (req.get('x-forwarded-proto') !== 'https') {
      res.redirect('https://' + req.hostname + req.originalUrl);
    } else
      next()
  });
}*/
app.use(compression());
app.use(favicon(path.join(__dirname, '..', 'static', 'favicon.ico')));

app.use(session({
  cookieName: 'session',
  secret: process.env.SESSION_SECRET,
  duration: 30 * 60 * 1000,
  activeDuration: 5 * 60 * 1000
}));

app.use((req, res, next) => {
  console.log(req.originalUrl);
  next();
})

app.use('/api', (req, res, next) => {
  if (req.session.secret === process.env.SESSION_SECRET) {
    next()
  } else {
    res.status(401).send('must call this route from the web page')
  }
});
app.use('/api/login', bodyParser.json());
app.post('/api/login', (req, res) => {
  request.post(process.env.API_URL + '/v1/auth/token')
    .set('Authorization', process.env.CLIENT_SECRET)
    .send(req.body)
    .end((err, result) => {
      if (err) {
        if (result.error) {
          res.status(400).send(result.body)
        }
      } else {
        req.session.user = result.body.auth.user;
        req.session.token = result.body.auth.token;
        res.send(result.body.auth.user);
      }
    });
});
app.get('/api/logout', (req, res) => {
  delete req.session.token;
  delete req.session.user;
  res.send();
});
proxy.on('proxyReq', (proxyReq, req, res, options) => {
  if (req.session.token) {
    proxyReq.setHeader('Authorization', req.session.token);
  } else {
    proxyReq.setHeader('Authorization', process.env.CLIENT_SECRET);
  }
});
app.use('/api', (req, res) => {
  proxy.web(req, res, {target: targetUrl});
});

app.use(Express.static(path.join(__dirname, '..', 'static')));

routes.forEach((route) => {
    try {
      if (route.middleware) {
        route.middleware.forEach((func) => {
          app[route.method](route.path, func);
        });
      }
      if (route.handler) {
        app[route.method](route.path, route.handler);
      }
    } catch(e) {
      console.error('Error at route ', route, e);
    }
  });

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err);
    }
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port);
  });
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified');
}
<commit_msg>New Logs<commit_after>import Express from 'express';
import config from './config';
import favicon from 'serve-favicon';
import compression from 'compression';
import path from 'path';
import PrettyError from 'pretty-error';
import http from 'http';
import httpProxy from 'http-proxy';
import session from 'client-sessions';
import bodyParser from 'body-parser'

import routes from './serverRoutes.map'

const targetUrl = process.env.API_URL;
const pretty = new PrettyError();
const app = new Express();
const server = new http.Server(app);
const proxy = httpProxy.createProxyServer({
  target: targetUrl
});

import request from 'superagent';

/*if (process.env.ENV === 'prod') {
  app.use((req, res, next) => {
    if (req.get('x-forwarded-proto') !== 'https') {
      res.redirect('https://' + req.hostname + req.originalUrl);
    } else
      next()
  });
}*/
app.use(compression());
app.use(favicon(path.join(__dirname, '..', 'static', 'favicon.ico')));

app.use(session({
  cookieName: 'session',
  secret: process.env.SESSION_SECRET,
  duration: 30 * 60 * 1000,
  activeDuration: 5 * 60 * 1000
}));

app.use('/api', (req, res, next) => {
  if (req.session.secret === process.env.SESSION_SECRET) {
    next()
  } else {
    res.status(401).send('must call this route from the web page')
  }
});
app.use('/api/login', bodyParser.json());
app.post('/api/login', (req, res) => {
  request.post(process.env.API_URL + '/v1/auth/token')
    .set('Authorization', process.env.CLIENT_SECRET)
    .send(req.body)
    .end((err, result) => {
      if (err) {
        if (result.error) {
          res.status(400).send(result.body)
        }
      } else {
        req.session.user = result.body.auth.user;
        req.session.token = result.body.auth.token;
        res.send(result.body.auth.user);
      }
    });
});
app.get('/api/logout', (req, res) => {
  delete req.session.token;
  delete req.session.user;
  res.send();
});
proxy.on('proxyReq', (proxyReq, req, res, options) => {
  if (req.session.token) {
    proxyReq.setHeader('Authorization', req.session.token);
  } else {
    proxyReq.setHeader('Authorization', process.env.CLIENT_SECRET);
  }
});
proxy.on('proxyRes', function (proxyRes, req, res) {
  console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
});
app.use('/api', (req, res) => {
  proxy.web(req, res, {target: targetUrl});
});

app.use(Express.static(path.join(__dirname, '..', 'static')));

routes.forEach((route) => {
    try {
      if (route.middleware) {
        route.middleware.forEach((func) => {
          app[route.method](route.path, func);
        });
      }
      if (route.handler) {
        app[route.method](route.path, route.handler);
      }
    } catch(e) {
      console.error('Error at route ', route, e);
    }
  });

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err);
    }
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port);
  });
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified');
}
<|endoftext|>


<commit_before>require('dotenv').config()

const path = require('path')
const bodyParser = require('body-parser')
const compression = require('compression')
const express = require('express')
const flash = require('connect-flash')
const csrf = require('csurf')
const slashify = require('slashify')
const churchill = require('churchill')
const enforce = require('express-sslify')
const favicon = require('serve-favicon')
const cookieParser = require('cookie-parser')
const minifyHTML = require('express-minify-html')
const proxy = require('http-proxy-middleware')
const Joi = require('@hapi/joi')

const config = require('./config')
const title = require('./middleware/title')
const breadcrumbs = require('./middleware/breadcrumbs')
const currentJourney = require('./modules/form/current-journey')
const nunjucks = require('./config/nunjucks')
const headers = require('./middleware/headers')
const locals = require('./middleware/locals')
const userLocals = require('./middleware/user-locals')
const metadata = require('./lib/metadata')
const user = require('./middleware/user')
const auth = require('./middleware/auth')
const store = require('./middleware/store')
const csrfToken = require('./middleware/csrf-token')
const errors = require('./middleware/errors')
const sessionStore = require('./middleware/session-store')
const ssoBypass = require('./middleware/sso-bypass')
const logger = require('./config/logger')
const basicAuth = require('./middleware/basic-auth')
const features = require('./middleware/features')
const redisCheck = require('./middleware/redis-check')
const reporter = require('./lib/reporter')
const permissions = require('./middleware/permissions')
const envSchema = require('./config/envSchema')
const flashWithBody = require('./middleware/flash-with-body')

const routers = require('./apps/routers')

const app = express()

// Validate ENV vars
Joi.assert(process.env, envSchema, {
  allowUnknown: true,
  abortEarly: false,
})

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

// Raven request handler must be the first middleware
reporter.setup(app)

if (!config.ci) {
  app.use(churchill(logger))
}

if (config.forceHttps) {
  app.enable('trust proxy')
  app.use(
    enforce.HTTPS({
      trustProtoHeader: true,
    })
  )
}

app.use(cookieParser())
app.use(compression())

app.set('view engine', 'njk')
nunjucks(app, config)

app.use(
  minifyHTML({
    override: true,
    exception_url: false,
    htmlMinifier: {
      removeComments: true,
      collapseInlineTagWhitespace: false,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeEmptyAttributes: true,
      minifyJS: true,
    },
  })
)

// Static files
app.use(favicon(path.join(config.root, 'public/images', 'favicon.ico')))
app.use(express.static(path.join(config.root, 'public')))
app.use('/js', express.static(path.join(config.buildDir, 'js')))
app.use('/css', express.static(path.join(config.buildDir, 'css')))
app.use('/images', express.static(path.join(config.buildDir, 'images')))
app.use('/fonts', express.static(path.join(config.buildDir, 'fonts')))
app.use(
  '/assets',
  express.static(path.join(config.root, 'node_modules/govuk-frontend/assets'))
)

app.use(title())
app.use(breadcrumbs.init())
app.use(breadcrumbs.setHome())
app.use(locals)
app.use(redisCheck)

app.use(sessionStore)

app.use(bodyParser.urlencoded({ extended: true, limit: '1mb' }))
app.use(bodyParser.json())

app.use(currentJourney())

app.use(flash())
app.use(flashWithBody)

app.use(ssoBypass())
app.use(basicAuth)
app.use(auth)
app.use(user)
app.use(permissions)
app.use(features)
app.use(userLocals)
app.use(headers)
app.use(store())
app.use(csrf())
app.use(csrfToken())

const API_PROXY_PATH = '/api-proxy'
app.use(
  proxy(
    config.apiProxyWhitelist.map((pth) => path.join(API_PROXY_PATH, pth)),
    {
      changeOrigin: true,
      target: config.apiRoot,
      pathRewrite: {
        ['^' + API_PROXY_PATH]: '',
      },
      onProxyReq: (proxyReq, req) =>
        proxyReq.setHeader('authorization', `Bearer ${req.session.token}`),
    }
  )
)

// routing
app.use(slashify())
app.use(routers)

// Raven error handler must come before other error middleware
reporter.handleErrors(app)

app.use(errors.notFound)
app.use(errors.catchAll)

metadata.fetchAll((errors) => {
  if (errors) {
    logger.log(
      'error',
      'Unable to load all metadataRepository, cannot start app'
    )

    for (const err of errors) {
      throw err
    }
  } else {
    app.listen(config.port, () => {
      logger.log('info', 'app listening on port %s', config.port)
    })
  }
})
<commit_msg>refactor api-proxy to handle POST requests<commit_after>require('dotenv').config()

const path = require('path')
const bodyParser = require('body-parser')
const compression = require('compression')
const express = require('express')
const flash = require('connect-flash')
const csrf = require('csurf')
const slashify = require('slashify')
const churchill = require('churchill')
const enforce = require('express-sslify')
const favicon = require('serve-favicon')
const cookieParser = require('cookie-parser')
const minifyHTML = require('express-minify-html')
const proxy = require('http-proxy-middleware')
const Joi = require('@hapi/joi')

const config = require('./config')
const title = require('./middleware/title')
const breadcrumbs = require('./middleware/breadcrumbs')
const currentJourney = require('./modules/form/current-journey')
const nunjucks = require('./config/nunjucks')
const headers = require('./middleware/headers')
const locals = require('./middleware/locals')
const userLocals = require('./middleware/user-locals')
const metadata = require('./lib/metadata')
const user = require('./middleware/user')
const auth = require('./middleware/auth')
const store = require('./middleware/store')
const csrfToken = require('./middleware/csrf-token')
const errors = require('./middleware/errors')
const sessionStore = require('./middleware/session-store')
const ssoBypass = require('./middleware/sso-bypass')
const logger = require('./config/logger')
const basicAuth = require('./middleware/basic-auth')
const features = require('./middleware/features')
const redisCheck = require('./middleware/redis-check')
const reporter = require('./lib/reporter')
const permissions = require('./middleware/permissions')
const envSchema = require('./config/envSchema')
const flashWithBody = require('./middleware/flash-with-body')

const routers = require('./apps/routers')

const app = express()

// Validate ENV vars
Joi.assert(process.env, envSchema, {
  allowUnknown: true,
  abortEarly: false,
})

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

// Raven request handler must be the first middleware
reporter.setup(app)

if (!config.ci) {
  app.use(churchill(logger))
}

if (config.forceHttps) {
  app.enable('trust proxy')
  app.use(
    enforce.HTTPS({
      trustProtoHeader: true,
    })
  )
}

app.use(cookieParser())
app.use(compression())

app.set('view engine', 'njk')
nunjucks(app, config)

app.use(
  minifyHTML({
    override: true,
    exception_url: false,
    htmlMinifier: {
      removeComments: true,
      collapseInlineTagWhitespace: false,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeEmptyAttributes: true,
      minifyJS: true,
    },
  })
)

// Static files
app.use(favicon(path.join(config.root, 'public/images', 'favicon.ico')))
app.use(express.static(path.join(config.root, 'public')))
app.use('/js', express.static(path.join(config.buildDir, 'js')))
app.use('/css', express.static(path.join(config.buildDir, 'css')))
app.use('/images', express.static(path.join(config.buildDir, 'images')))
app.use('/fonts', express.static(path.join(config.buildDir, 'fonts')))
app.use(
  '/assets',
  express.static(path.join(config.root, 'node_modules/govuk-frontend/assets'))
)

app.use(title())
app.use(breadcrumbs.init())
app.use(breadcrumbs.setHome())
app.use(locals)
app.use(redisCheck)

app.use(sessionStore)

app.use(bodyParser.urlencoded({ extended: true, limit: '1mb' }))
app.use(bodyParser.json())

app.use(currentJourney())

app.use(flash())
app.use(flashWithBody)
app.use(ssoBypass())
app.use(basicAuth)
app.use(auth)
app.use(user)
app.use(permissions)
app.use(features)
app.use(userLocals)
app.use(headers)
app.use(store())

const API_PROXY_PATH = '/api-proxy'
app.use(
  proxy(
    config.apiProxyWhitelist.map((pth) => path.join(API_PROXY_PATH, pth)),
    {
      changeOrigin: true,
      target: config.apiRoot,
      pathRewrite: {
        ['^' + API_PROXY_PATH]: '',
      },
      onProxyReq: (proxyReq, req) => {
        proxyReq.setHeader('authorization', `Bearer ${req.session.token}`)
        // this is required to be able to handle POST requests and avoid a conflict with bodyParser
        // issue here -> https://github.com/chimurai/http-proxy-middleware/issues/320
        if (req.body) {
          let bodyData = JSON.stringify(req.body)
          // incase if content-type is application/x-www-form-urlencoded -> we need to change to application/json
          proxyReq.setHeader('Content-Type', 'application/json')
          proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData))
          // stream the content
          proxyReq.write(bodyData)
        }
      },
    }
  )
)

app.use(csrf())
app.use(csrfToken())
// routing
app.use(slashify())
app.use(routers)

// Raven error handler must come before other error middleware
reporter.handleErrors(app)

app.use(errors.notFound)
app.use(errors.catchAll)

metadata.fetchAll((errors) => {
  if (errors) {
    logger.log(
      'error',
      'Unable to load all metadataRepository, cannot start app'
    )

    for (const err of errors) {
      throw err
    }
  } else {
    app.listen(config.port, () => {
      logger.log('info', 'app listening on port %s', config.port)
    })
  }
})
<|endoftext|>


<commit_before>const http = require("http");
const createDebug = require('debug');
const chalk = require('chalk');
const Handler = require("./handlers");
const Library = require("./library");

const debug = createDebug('nails:server');
const log = createDebug('nails');

exports = module.exports = class Server {
  constructor(config) {
    this.handler = new Handler(config);
    this.config = config;
  }
  run() {
    this.handler.ready.then(this._run.bind(this));
  }
  _run() {
    debug('starting server...');
    const iface = this.config.server_interface;
    const port = this.config.server_port;
    const server = http.createServer((req, res) => {
      log(req.method, chalk.underline(req.url), `HTTP/${req.httpVersion}`);

      const requestHandler = this.handler.getHandler(req);
      if (requestHandler) {
        const library = new Library();
        const prom = requestHandler.call(library.context, req);
        Promise.resolve(prom).then(() => {
          let opts = library.requestData;

          if (opts != null) {
            if (opts.redirect_to) {
              res.writeHead(302, {
                location: opts.redirect_to,
                'Turbolinks-Location': opts.redirect_to
              });
              res.end();
            }
            else {
              opts = Object.assign(opts, {routes: this.handler.routes});
              Handler.renderer(req, res, opts);
            }
          }
        });
      }
      else {
        Handler.getStaticContent("404.html", this.config).then(customErrorPage => {
          if (customErrorPage) {
            res.statusCode = 404;
            Handler.renderer(req, res, {
              routes: this.handler.routes,
              content: customErrorPage
            });
          }
          else {
            res.writeHead(404, 'Not Found');
            res.end();
          }
          log('404 at', req.url);
        });
      }
    });

    server.listen(port, iface, () => {
      log('Listening on', `${iface}:${port}`);
    });
  }
};
<commit_msg>Move request handler to separate method<commit_after>const http = require("http");
const createDebug = require('debug');
const chalk = require('chalk');
const Handler = require("./handlers");
const Library = require("./library");

const debug = createDebug('nails:server');
const log = createDebug('nails');

exports = module.exports = class Server {
  constructor(config) {
    this.handler = new Handler(config);
    this.config = config;
  }
  run() {
    this.handler.ready.then(this._run.bind(this));
  }
  _run() {
    debug('starting server...');
    const iface = this.config.server_interface;
    const port = this.config.server_port;
    const server = http.createServer(this._handleRequest.bind(this));

    server.listen(port, iface, () => {
      console.log("Nails server listening on " + iface + ":" + port);
    });
  }
  _handleRequest(req, res) {
    log(req.method, chalk.underline(req.url), `HTTP/${req.httpVersion}`);

    const requestHandler = this.handler.getHandler(req);
    if (requestHandler) {
      const library = new Library();
      const prom = requestHandler.call(library.context, req);
      Promise.resolve(prom).then(() => {
        let opts = library.requestData;

        if (opts != null) {
          if (opts.redirect_to) {
            res.writeHead(302, {
              location: opts.redirect_to,
              'Turbolinks-Location': opts.redirect_to
            });
            res.end();
          }
          else {
            opts = Object.assign(opts, {routes: this.handler.routes});
            Handler.renderer(req, res, opts);
          }
        }
      });
    }
    else {
      Handler.getStaticContent("404.html", this.config).then(customErrorPage => {
        if (customErrorPage) {
          res.statusCode = 404;
          Handler.renderer(req, res, {
            routes: this.handler.routes,
            content: customErrorPage
          });
        }
        else {
          res.writeHead(404, 'Not Found');
          res.end();
        }
        log('404 at', req.url);
      });
    }
  }
};
<|endoftext|>


<commit_before>require('babel/polyfill');
let Path = require('path');
let Hapi = require('hapi');
var Good = require('good');
var _ = require('underscore');
import {setupRedirects} from './redirects.js';
import {reloadData, blogPosts, blogPostsByYear, blogPostsByTag, rssByTag, feed, tags} from './cache.js';
import {slicePostsForPage, newFeedFromTag} from './helpers.js';
import {addComment, getComments} from './datastore.js';

reloadData();

let server = new Hapi.Server({
  connections: {
    router: {
      stripTrailingSlash: false,
    },
    routes: {
      files: {
        relativeTo: Path.join(__dirname, 'public')
      }
    }
  }
});
server.connection({ port: process.env.PORT || 3000 });
setupRedirects(server);

let indexPaths = ['/{name}', '/other/{name}', '/compression/{name}', '/math/{name}', '/mozilla/new',
  '/', '/blog', '/blog/posted/{year}', '/blog/tagged/{tag}', '/blog/{id}',
  '/page/{page}', '/blog/page/{page}', '/blog/posted/{year}/page/{page}', '/blog/tagged/{tag}/page/{page}',
  '/stackexchange-twitter/{page}', '/stackexchange-linkedin/{page}', '/stackexchange-facebook/{page}',
  ];

indexPaths.forEach(path => {
  server.route({
    method: 'GET',
    path: path,
    handler: function (request, reply) {
      reply.file('index.html');
    }
  });
});

server.route({
  method: 'GET',
  path: '/refresh',
  handler: function (request, reply) {
    reloadData();
    reply.redirect('/');
  }
});

server.route({
  method: 'GET',
  path: '/feeds/rss',
  handler: function (request, reply) {
    reply(feed.xml({indent: true})).type('application/rss+xml');
  }
});

server.route({
  method: 'GET',
  path: '/feeds/rss/{tag}',
  handler: function (request, reply) {
    var feedByTag = rssByTag[request.params.tag] || newFeedFromTag(request.params.tag);
    reply(feedByTag.xml({indent: true})).type('application/rss+xml');
  }
});

server.route({
  method: 'GET',
  path: '/api/tags',
  handler: function (request, reply) {
    reply(tags).code(200);
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/posted/{year}',
  handler: function (request, reply) {
    let posts = blogPostsByYear[request.params.year] || [];
    reply(slicePostsForPage(posts, request.query.page)).code(200);
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/tagged/{tag}',
  handler: function (request, reply) {
    let posts = blogPostsByTag[request.params.tag] || [];
    reply(slicePostsForPage(posts, request.query.page)).code(200);
  }
});

server.route({
  method: 'POST',
  path: '/api/blog/{id}/comments',
  handler: function (request, reply) {
    addComment(request.query.id, request.payload)
      .then(() => reply().code(200))
      .catch(() => reply('Error posting comment to Redis').code(500));
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/{id}/comments',
  handler: function (request, reply) {
    getComments(request.query.id)
      .then(() => reply().code(200))
      .catch(() => reply('Error obtaining comments from Redis').code(500));
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/{id}',
  handler: function (request, reply) {
    let blogPost = _(blogPosts).find(post =>
      post.id === Number(request.params.id));
    reply(blogPost).code(200);
  }
});

server.route({
  method: 'GET',
  path: '/api/blog',
  handler: function (request, reply) {
    reply(slicePostsForPage(blogPosts, request.query.page)).code(200);
  }
});

// Serve everythign else from the public folder
server.route({
  method: 'GET',
  path: '/{path*}',
  handler: {
    directory: {
      path: './'
    }
  }
});

// Serve everythign else from the public folder
server.route({
  method: 'GET',
  path: '/static/{path*}',
  handler: {
    directory: {
      path: './'
    }
  }
});

server.register({
  register: Good,
  options: {
    reporters: [{
      reporter: require('good-console'),
      events: {
        response: '*',
        log: '*'
      }
    }]
  }
}, function (err) {
  if (err) {
    throw err; // something bad happened loading the plugin
  }

  server.start(function () {
    server.log('info', 'Server running at: ' + server.info.uri);
  });
});
<commit_msg>Server should initRedis before using<commit_after>require('babel/polyfill');
let Path = require('path');
let Hapi = require('hapi');
var Good = require('good');
var _ = require('underscore');
import {setupRedirects} from './redirects.js';
import {reloadData, blogPosts, blogPostsByYear, blogPostsByTag, rssByTag, feed, tags} from './cache.js';
import {slicePostsForPage, newFeedFromTag} from './helpers.js';
import {initRedis, addComment, getComments} from './datastore.js';

initRedis(process.env.REDIS_PORT);
reloadData();

let server = new Hapi.Server({
  connections: {
    router: {
      stripTrailingSlash: false,
    },
    routes: {
      files: {
        relativeTo: Path.join(__dirname, 'public')
      }
    }
  }
});
server.connection({ port: process.env.PORT || 3000 });
setupRedirects(server);

let indexPaths = ['/{name}', '/other/{name}', '/compression/{name}', '/math/{name}', '/mozilla/new',
  '/', '/blog', '/blog/posted/{year}', '/blog/tagged/{tag}', '/blog/{id}',
  '/page/{page}', '/blog/page/{page}', '/blog/posted/{year}/page/{page}', '/blog/tagged/{tag}/page/{page}',
  '/stackexchange-twitter/{page}', '/stackexchange-linkedin/{page}', '/stackexchange-facebook/{page}',
  ];

indexPaths.forEach(path => {
  server.route({
    method: 'GET',
    path: path,
    handler: function (request, reply) {
      reply.file('index.html');
    }
  });
});

server.route({
  method: 'GET',
  path: '/refresh',
  handler: function (request, reply) {
    reloadData();
    reply.redirect('/');
  }
});

server.route({
  method: 'GET',
  path: '/feeds/rss',
  handler: function (request, reply) {
    reply(feed.xml({indent: true})).type('application/rss+xml');
  }
});

server.route({
  method: 'GET',
  path: '/feeds/rss/{tag}',
  handler: function (request, reply) {
    var feedByTag = rssByTag[request.params.tag] || newFeedFromTag(request.params.tag);
    reply(feedByTag.xml({indent: true})).type('application/rss+xml');
  }
});

server.route({
  method: 'GET',
  path: '/api/tags',
  handler: function (request, reply) {
    reply(tags).code(200);
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/posted/{year}',
  handler: function (request, reply) {
    let posts = blogPostsByYear[request.params.year] || [];
    reply(slicePostsForPage(posts, request.query.page)).code(200);
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/tagged/{tag}',
  handler: function (request, reply) {
    let posts = blogPostsByTag[request.params.tag] || [];
    reply(slicePostsForPage(posts, request.query.page)).code(200);
  }
});

server.route({
  method: 'POST',
  path: '/api/blog/{id}/comments',
  handler: function (request, reply) {
    addComment(request.query.id, request.payload)
      .then(() => reply().code(200))
      .catch(() => reply('Error posting comment to Redis').code(500));
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/{id}/comments',
  handler: function (request, reply) {
    getComments(request.query.id)
      .then(() => reply().code(200))
      .catch(() => reply('Error obtaining comments from Redis').code(500));
  }
});

server.route({
  method: 'GET',
  path: '/api/blog/{id}',
  handler: function (request, reply) {
    let blogPost = _(blogPosts).find(post =>
      post.id === Number(request.params.id));
    reply(blogPost).code(200);
  }
});

server.route({
  method: 'GET',
  path: '/api/blog',
  handler: function (request, reply) {
    reply(slicePostsForPage(blogPosts, request.query.page)).code(200);
  }
});

// Serve everythign else from the public folder
server.route({
  method: 'GET',
  path: '/{path*}',
  handler: {
    directory: {
      path: './'
    }
  }
});

// Serve everythign else from the public folder
server.route({
  method: 'GET',
  path: '/static/{path*}',
  handler: {
    directory: {
      path: './'
    }
  }
});

server.register({
  register: Good,
  options: {
    reporters: [{
      reporter: require('good-console'),
      events: {
        response: '*',
        log: '*'
      }
    }]
  }
}, function (err) {
  if (err) {
    throw err; // something bad happened loading the plugin
  }

  server.start(function () {
    server.log('info', 'Server running at: ' + server.info.uri);
  });
});
<|endoftext|>


<commit_before>/* eslint consistent-return: 0 */
import express from 'express'
import morgan from 'morgan'
import bodyParser from 'body-parser'
import { getFileContents } from './utils'
import { HELP_MESSAGE, EMPTY_REQUEST, ERROR_MESSAGE } from './constants'

const { BS_USERNAME, BS_AUTHTOKEN, SLACK_VERIFY_TOKEN, PORT } = process.env
if (!SLACK_VERIFY_TOKEN) {
    console.error('SLACK_VERIFY_TOKEN is required')
    process.exit(1)
}
if (!PORT) {
    console.error('PORT is required')
    process.exit(1)
}

const app = express()
app.use(morgan('dev'))

app.route('/code')
    .get((req, res) => {
        res.sendStatus(200)
    })
    .post(bodyParser.urlencoded({ extended: true }), (req, res) => {
        if (req.body.token !== SLACK_VERIFY_TOKEN) {
            return res.sendStatus(401)
        }

        const { text } = req.body

        // Handle empty request
        if (!text) {
            return res.json({
                response_type: 'ephemeral',
                text: EMPTY_REQUEST
            })
        }

        // Handle any help requests
        if (text === 'help') {
            return res.json({
                response_type: 'ephemeral',
                text: HELP_MESSAGE
            })
        }

        getFileContents(text, {
            username: BS_USERNAME,
            token: BS_AUTHTOKEN
        }, (err, content) => {
            if (err) {
                return res.json({
                    response_type: 'ephemeral',
                    text: `${ ERROR_MESSAGE } ${ err.message }`
                })
            }

            return res.json({
                response_type: 'ephemeral',
                ...content
            })
        })
    })

app.listen(PORT, (err) => {
    if (err) {
        return console.error('Error starting server: ', err)
    }

    return console.log('Server successfully started on port %s', PORT)
})
<commit_msg>Consistent auth token as start example<commit_after>/* eslint consistent-return: 0 */
import express from 'express'
import morgan from 'morgan'
import bodyParser from 'body-parser'
import { getFileContents } from './utils'
import { HELP_MESSAGE, EMPTY_REQUEST, ERROR_MESSAGE } from './constants'

const { BS_USERNAME, BS_AUTH_TOKEN, SLACK_VERIFY_TOKEN, PORT } = process.env
if (!SLACK_VERIFY_TOKEN) {
    console.error('SLACK_VERIFY_TOKEN is required')
    process.exit(1)
}
if (!PORT) {
    console.error('PORT is required')
    process.exit(1)
}

const app = express()
app.use(morgan('dev'))

app.route('/code')
    .get((req, res) => {
        res.sendStatus(200)
    })
    .post(bodyParser.urlencoded({ extended: true }), (req, res) => {
        if (req.body.token !== SLACK_VERIFY_TOKEN) {
            return res.sendStatus(401)
        }

        const { text } = req.body

        // Handle empty request
        if (!text) {
            return res.json({
                response_type: 'ephemeral',
                text: EMPTY_REQUEST
            })
        }

        // Handle any help requests
        if (text === 'help') {
            return res.json({
                response_type: 'ephemeral',
                text: HELP_MESSAGE
            })
        }

        getFileContents(text, {
            username: BS_USERNAME,
            token: BS_AUTH_TOKEN
        }, (err, content) => {
            if (err) {
                return res.json({
                    response_type: 'ephemeral',
                    text: `${ ERROR_MESSAGE } ${ err.message }`
                })
            }

            return res.json({
                response_type: 'ephemeral',
                ...content
            })
        })
    })

app.listen(PORT, (err) => {
    if (err) {
        return console.error('Error starting server: ', err)
    }

    return console.log('Server successfully started on port %s', PORT)
})
<|endoftext|>


<commit_before>/*
* Shaker command!
*/
var path = require('path'),
    utils = require('mojito/lib/management/utils'),
    fs = require('fs'),
	ResourceStore = require('mojito/lib/store.server'),
    Queue = require('buildy').Queue,
    Registry = require('buildy').Registry,

    run,usage,options,

/* GLOBAL */
    MODULES_BAREBONES = [];

usage =  "mojito compile {options} {type}\n" +
       "\nOPTIONS: \n" +
       "\t --rollup-mojito     :  remove all compiled files, instead of creating them\n" +
       "\t  -rm                :  short for --rollup-mojito\n" +
       "\t --output     :  send the output to a specific folder\n" +
       "\t  -rm                :  short for --output\n" +

		"\nTYPES: \n" +
		"\t all                    performs all the other types\n";

options = [
    {
        shortName: 'rm',
        longName: 'rollup-mojito',
        hasValue: false
    },
    {
        shortName: 'o',
        longName: 'output',
        hasValue: false
    },
    {
        shortName: 's',
        longName: 'setup',
        hasValue: false
    },
    {
        shortName: 'b',
        longName: 'build',
        hasValue: false
    }
];

function rollupMojito(params,options,callback){
	var type = params.shift(),list;
	if(!type) {
		utils.error("Please provide the type of rollup you want.", exports.usage, true);
		return;
	}
	switch(type){
		case 'full': break;
		case 'barebones': list = MODULES_BAREBONES ;break;
		case 'modules' : list = ['modules']; break;
		default: utils.error("Please provide a valid type of rollup.", exports.usage, true); return;
	}
	options.outputPath = options.output ? params.shift(): true;
	options.type = type;
	generateRollup(list,options,callback);

}

function generateRollup(list,options,callback){
	var cwd = process.cwd(),
		store = new ResourceStore(cwd),
		dest = options.outputPath || cwd+'/artifacts/shaker',
		fileName = 'rollup_'+ options.type + '.js',
		modules,rolledModules = [],rollupBody = '',
		context = {},
		filterModules = function (item){
			var moduleName = path.basename(i,'.js');
			for(var i = 0; i < list.length; i++){
				if(moduleName === list[item]) return true;
			}
			return false;
		};
	//get an filter the files from the store
	store.preload();
	var rollupMojito = (store.getRollupsApp('client', context)).srcs;
	modules = list ? rollupMojito.filter(filterModules) : rollupMojito;
	for(var j = 0; j < modules.length; j++){
		if(cwd === modules[j].substr(0, cwd.length)) {
            //skip the app level files (Note: to override path: substr(cwd.length + 1);)
            continue;
        }
        rolledModules.push(modules[j]);
        rollupBody += fs.readFileSync(modules[j], 'utf-8');
    }
    //output a file
    if(options.output){
			utils.makeDir(dest);
			fs.writeFileSync(dest+'/'+fileName, rollupBody, 'utf-8');
			callback();
    }
    //output inline
    else{
        processRollup(rolledModules, function(filename) {
            console.log(filename);
        });
    }
}

function processRollup(files, callback) {
    var registry = new Registry();
    registry.load(__dirname + '/lib/tasks/checksumwrite.js');

    var queue = new Queue('MojitoRollup', {registry: registry});

    queue.on('taskComplete', function(data) {
        if (data.task.type === 'checksumwrite') {
            callback(data.result);
        }
    });

    queue.task('files', files)
        .task('concat')
        .task('jsminify')
        .task('checksumwrite', {name: 'mojito_rollup_{checksum}.js'})
        .run();
}

function buildShaker(params,options,callback){
	require(process.cwd()+'/node_modules/shaker');
}

run = function(params, options, callback){
	var context = {};
	options = options || {};

	switch(true){
		case options['rollup-mojito'] :  rollupMojito(params,options,callback); break;
		//case options.setup : setupShaker(params); break;
		case options.build : buildShaker(); break;
		default: utils.error("Please provide the type of compilation you want.", exports.usage, true);
	}
};

exports.usage = usage;
exports.options = options;
exports.run = run;
<commit_msg>Shaker command now rolling up mojito and app level files<commit_after>/*
* Shaker command!
*/
var path = require('path'),
    utils = require('mojito/lib/management/utils'),
    fs = require('fs'),
	ResourceStore = require('mojito/lib/store.server'),
    Queue = require('buildy').Queue,
    Registry = require('buildy').Registry,
    Shaker = require('./lib/core').Shaker,

    run,usage,options,

/* GLOBAL */
    MODULES_BAREBONES = [];

usage =  "mojito compile {options} {type}\n" +
       "\nOPTIONS: \n" +
       "\t --rollup-mojito     :  remove all compiled files, instead of creating them\n" +
       "\t  -rm                :  short for --rollup-mojito\n" +
       "\t --output     :  send the output to a specific folder\n" +
       "\t  -rm                :  short for --output\n" +

		"\nTYPES: \n" +
		"\t all                    performs all the other types\n";

options = [
    {
        shortName: 'rm',
        longName: 'rollup-mojito',
        hasValue: false
    },
    {
        shortName: 'o',
        longName: 'output',
        hasValue: false
    },
    {
        shortName: 's',
        longName: 'setup',
        hasValue: false
    },
    {
        shortName: 'b',
        longName: 'build',
        hasValue: false
    }
];

function rollupMojito(params,options,callback){
	var type = params.shift(),list;
	if(!type) {
		utils.error("Please provide the type of rollup you want.", exports.usage, true);
		return;
	}
	switch(type){
		case 'full': break;
		case 'barebones': list = MODULES_BAREBONES ;break;
		case 'modules' : list = ['modules']; break;
		default: utils.error("Please provide a valid type of rollup.", exports.usage, true); return;
	}
	options.outputPath = options.output ? params.shift(): true;
	options.type = type;
	generateRollup(list,options,callback);

}

function generateRollup(list,options,callback){
	var cwd = process.cwd(),
		store = new ResourceStore(cwd),
		dest = options.outputPath || cwd+'/artifacts/shaker',
		fileName = 'rollup_'+ options.type + '.js',
		modules,rolledModules = [],rollupBody = '',
		context = {},
		filterModules = function (item){
			var moduleName = path.basename(i,'.js');
			for(var i = 0; i < list.length; i++){
				if(moduleName === list[item]) return true;
			}
			return false;
		};
	//get an filter the files from the store
	store.preload();
	var rollupMojito = (store.getRollupsApp('client', context)).srcs;
	modules = list ? rollupMojito.filter(filterModules) : rollupMojito;
	for(var j = 0; j < modules.length; j++){
		if(cwd === modules[j].substr(0, cwd.length)) {
            //skip the app level files (Note: to override path: substr(cwd.length + 1);)
            continue;
        }
        rolledModules.push(modules[j]);
        rollupBody += fs.readFileSync(modules[j], 'utf-8');
    }
    //output a file
    if(options.output){
			utils.makeDir(dest);
			fs.writeFileSync(dest+'/'+fileName, rollupBody, 'utf-8');
			callback();
    }
    //output inline
    else{
        var results = [];

        processRollup(rolledModules, 'mojito_rollup', '.js', function(filename) {
            transformedRollup(filename);
        });

        var shaker = new Shaker({root: './'});
        shaker.shakeAll(function(shaken){
            var modules = [
                {name: 'master', module: shaken.mojits.master['*'].shaken},
                {name: 'primary', module: shaken.mojits.primary['*'].shaken},
                {name: 'secondary', module: shaken.mojits.secondary['*'].shaken},
                {name: 'app', module: shaken.app['*'].shaken}
            ];

            modules.forEach(function(module) {
                for (var type in module.module) {
                    processRollup(module.module[type], module.name + '-' + type, '.css', transformedRollup);
                }
            });
        });
    }
}

function transformedRollup(filename) {
    console.log(filename);
}

function processRollup(files, name, ext, callback) {
    var registry = new Registry();
    registry.load(__dirname + '/lib/tasks/checksumwrite.js');

    var queue = new Queue('MojitoRollup', {registry: registry});

    queue.on('taskComplete', function(data) {
        if (data.task.type === 'checksumwrite') {
            callback(data.result);
        }
    });

    queue.task('files', files)
        .task('concat')
        .task(ext === '.js' ? 'jsminify' : 'cssminify')
        .task('checksumwrite', {name: name + '_{checksum}' + ext})
        .run();
}

function buildShaker(params,options,callback){
	require(process.cwd()+'/node_modules/shaker');
}

run = function(params, options, callback){
	var context = {};
	options = options || {};

	switch(true){
		case options['rollup-mojito'] :  rollupMojito(params,options,callback); break;
		//case options.setup : setupShaker(params); break;
		case options.build : buildShaker(); break;
		default: utils.error("Please provide the type of compilation you want.", exports.usage, true);
	}
};

exports.usage = usage;
exports.options = options;
exports.run = run;
<|endoftext|>