<|start_filename|>controllers/home.js<|end_filename|>
'use strict';

module.exports = function(app) {

	app.get('/', function(req, res) {

		if (req.isAuthenticated()) {
			// Already logged in.
			var loggedMessage = 'You are logged';
		}

		app.db.select([
			'projects.id',
			'projects.name',
			'projects.description',
			'projects.goal_amount',
			'project_addresses.token'
		])
		.from('projects')
		.leftJoin('project_addresses', 'projects.id', 'project_addresses.project_id')
		.then(function(projects) {
			res.render('home', {
				projects: projects,
				loggedMessage: loggedMessage
			});
		}).catch(console.log);
	});
};


<|start_filename|>middleware/template.js<|end_filename|>
'use strict';

module.exports = function(app) {

	var exphbr = require('express-handlebars');

	app.engine('html', exphbr({
		defaultLayout: 'main',
		extname: '.html'
	}));

	app.set('view engine', 'html');
};


<|start_filename|>controllers/projects/view.js<|end_filename|>
'use strict'

module.exports = function(app) {

	app.get('/projects/:id', function(req, res) {
		res.send('Not done yet.');
	});
};


<|start_filename|>controllers/projects/delete.js<|end_filename|>
'use strict'

module.exports = function(app) {

	app.get('/projects/delete/:id', app.middleware.requireAuthentication, function(req, res) {
		var id = req.params.id;
		app.db.transaction(function(trx) {
			// Note: make sure an address can be assigned to 1 project only or that no other project uses it
			app.db('project_addresses')
				.transacting(trx)
				.where('project_id', id)
				.del()
				.catch(function(error) {
					console.log(error);
				})
				.then(
					app.db('projects')
					.where('id', id)
					.del()
					.catch(function(error) {
						console.log(error);
					})
				)
				.then(trx.commit)
				.catch(trx.rollback)
				.catch(function(error) {
					console.log(error);
				})
				.finally(function() {
					res.redirect('../../')

				})
		})

	});
};


<|start_filename|>models/Projects.js<|end_filename|>
'use strict';

var BaseModel = require('./BaseModel');

module.exports = BaseModel.extend({

	tableName: 'projects',

	defineSchema: function(table) {

		BaseModel.defineSchema.apply(this, arguments);

		table.increments('id');
		table.string('name');
		table.string('description');
		table.decimal('goal_amount', 16, 8);
	}

});


<|start_filename|>models/BaseModel.js<|end_filename|>
'use strict';

var _ = require('underscore');
var async = require('async');
var db = require('../database');

module.exports = {

	tableName: null,

	query: function() {

		return db(this.tableName);
	},

	defineSchema: function(table) {

		// Meant to be overwritten.
	},

	setUpTable: function(cb) {

		if (!this.defineSchema || !this.tableName) {
			return cb();
		}

		var tableName = this.tableName;
		var defineSchema = _.bind(this.defineSchema, this);
		var schemaChanges = _.map(this.schemaChanges || [], function(fn) {
			return _.bind(fn, this);
		}, this);

		db.schema.hasTable(tableName).then(function(exists) {

			if (exists) {

				if (schemaChanges && !_.isEmpty(schemaChanges)) {
					// IMPORTANT: Make all schema changes in series (not parallel).
					return async.series(schemaChanges, cb);
				}

				return cb();
			}

			db.schema.createTable(tableName, defineSchema).then(function() {
				cb();
			}).catch(cb);

		}).catch(cb);
	},

	schemaChanges: [],

	queueSchemaChange: function(fn) {

		this.schemaChanges = _.clone(this.schemaChanges).concat(fn);
	},

	extend: function(obj) {

		return _.extend({}, this, obj);
	}

};


<|start_filename|>services/index.js<|end_filename|>
'use strict';

module.exports = {
	bitcoin: require('./bitcoin'),
};


<|start_filename|>middleware/index.js<|end_filename|>
'use strict';

module.exports = function(app) {

	app.middleware = {};

	/*
		!! IMPORTANT !!
		The order of middleware is significant. Do not re-order unless you understand what you're doing.
	*/
	require('./parsers')(app);
	require('./session')(app);
	require('./auth')(app);
	require('./logging')(app);
	require('./current_user')(app);
	require('./template')(app);
	require('./static')(app);
};


<|start_filename|>models/Users.js<|end_filename|>
'use strict';

var BaseModel = require('./BaseModel');

module.exports = BaseModel.extend({

	tableName: 'users',

	defineSchema: function(table) {

		BaseModel.defineSchema.apply(this, arguments);

		table.increments('id');
		table.string('username');
		table.string('password');
		table.string('email');
	}

});


<|start_filename|>middleware/session.js<|end_filename|>
'use strict';

module.exports = function(app) {

	var session = require('express-session');
	var MySQLStore = require('express-mysql-session')(session);
	var sessionStore = new MySQLStore(app.config.db);

	app.use(session({
		key: app.config.session.key,
		secret: app.config.session.secret,
		store: sessionStore,
		resave: false,
		saveUninitialized: true
	}));
};


<|start_filename|>services/bitcoin.js<|end_filename|>
'use strict';

var request = require('request');
var _ = require('underscore');

module.exports = {

	getFunds: function(addresses, cb) {

		var uri = 'https://blockchain.info/multiaddr?active=';
		uri += addresses.join('|');

		request(uri, function(error, response, body) {

			if (!error && response.statusCode == 200) {
				var obj = JSON.parse(body);
				var allAccountsReceived
				_.each(addresses, function(element, index) {
					allAccountsReceived += obj.addresses[index].total_received;
				});
				cb(allAccountsReceived);
			} else {
				console.log('There was an error')
			}
		});
	}
};


<|start_filename|>scripts/seed_projects.js<|end_filename|>
'use strict';

var db = require('../database');
var fs = require('fs');

// Get content from file
var contents = fs.readFileSync("./test/fixtures/projects.json");
// Define to JSON type
var seed_data = JSON.parse(contents);
projects = seed_data.projects;

function seed() {

	projects.forEach(function(project) {
		db('projects')
			.insert({
				name: project.name,
				description: project.description,
				goal_amount: project.goal_amount
			}).then(function(result) {
				db('project_addresses')
					.insert({
						project_id: result[0],
						token: project.token
					}).then(function() {
						process.exit();
					});
			}).catch(console.log);
	});
}

seed();

<|start_filename|>models/ProjectAddresses.js<|end_filename|>
'use strict';

var BaseModel = require('./BaseModel');

module.exports = BaseModel.extend({

	tableName: 'project_addresses',

	defineSchema: function(table) {

		BaseModel.defineSchema.apply(this, arguments);

		table.increments('id');
		table.integer('project_id').unsigned();
		table.foreign('project_id').references('projects.id');
		table.string('token');
	}

});


<|start_filename|>views/home.html<|end_filename|>
<h1>Bitstarter homepage</h1>

{{#if projects}}
	{{#each projects}}
		<section class='project'>
			<h2 class='name'>{{name}}</h2>
			<p class='description'>{{description}}</p>
			<p class='amount'>{{goal_amount}} Ƀ</p>
			<p class='token'>{{token}}</p>
      {{#if ../user}}
			<p>
						<a href="/projects/edit/{{id}}">Edit</a>
						<a href="/projects/delete/{{id}}">Delete</a>
			</p>
      {{/if}}
		</section>
	{{/each}}
{{else}}
	<p>No projects available.</p>
{{/if}}


<|start_filename|>grunt/aliases.json<|end_filename|>
{
	"default": [
		"test"
	],
	"test": [
		"test:unit",
		"test:integration",
		"test:code-style"
	],
	"test:code-style": [
		"eslint"
	],
	"test:unit": [
		"env:test",
		"mochaTest:unit"
	],
	"test:integration": [
		"env:test",
		"mochaTest:integration"
	]
}

<|start_filename|>controllers/projects/index.js<|end_filename|>
'use strict';

module.exports = function(app) {

	require('./add')(app);
	require('./delete')(app);
	require('./edit')(app);
	require('./view')(app);
};


<|start_filename|>config.js<|end_filename|>
'use strict';

module.exports = {

	db: {
		host: process.env.BITSTARTER_DB_HOST || '127.0.0.1',
		port: parseInt(process.env.BITSTARTER_DB_PORT || 3306),
		user: process.env.BITSTARTER_DB_USER || 'bitstarter',
		password: process.env.BITSTARTER_DB_PASS || 'password',
		database: process.env.BITSTARTER_DB_NAME || 'bitstarter'
	},

	session: {
		key: process.env.BITSTARTER_SESSION_KEY || 'bitstarter.sid',
		secret: process.env.BITSTARTER_SESSION_SECRET || 'default not-so secret'
	}
};


<|start_filename|>public/css/style.css<|end_filename|>
body {
  background-color: #1A1A1A;
  color: #FBFBFB;
}

h1 {
  color: #FBFBFB;
}

a {
  color: #FBFBFB;
  text-decoration: none;
}

.header {
  text-align: right;
  color: #E6E6E6;
}

.project {
  margin: 10px;
  width: 30%;
  float: left;
  color: #E6E6E6;
  min-width: 200px;
  overflow: hidden;
}

.project .name {
  color: #1ABE7B;
}


<|start_filename|>test/integration/controllers/login.js<|end_filename|>
'use strict';

var chai = require('chai');
var chaiHttp = require('chai-http');
var expect = require('chai').expect;
chai.use(chaiHttp);

var manager = require('../../manager');

describe('testing login.js and logout.js', function() {

	before(manager.setUp);
	after(manager.tearDown);

	it('testing get /login', function(done){
		chai.request('http://localhost:3000/')
		.get('login')
		.end(function(err, res){
			expect(res).to.have.status(200);
			done();
		});
	});
});


<|start_filename|>grunt/eslint.js<|end_filename|>
'use strict';

module.exports = {
	options: {
		configFile: '.eslintrc.js',
		ignorePath: '.eslintignore'
	},
	files: [
		'Gruntfile.js',
		'controllers/**/*.js',
		'scripts/**/*.js',
		'services/**/*.js',
		'test/**/*.js'
	]
};


<|start_filename|>controllers/logout.js<|end_filename|>
'use strict'

module.exports = function(app) {

	app.get('/logout', function(req, res) {

		if (req.isAuthenticated()) {
			// Destroy their current session to be sure they are logged out.
			// This is important because the session might contain data related to their user account.
			req.session.destroy(function() {
				// Send them to the login page.
				res.redirect('/login');
			});
		} else {
			// They are already logged out.
			// Send them to the login page.
			res.redirect('/login');
		}
	});

}; // close module.exports


<|start_filename|>grunt/watch.js<|end_filename|>
'use strict';

module.exports = {
	tasks: ['eslint'],
	files: [
		'Gruntfile.js',
		'controllers/**/*.js',
		'scripts/**/*.js',
		'services/**/*.js',
		'test/**/*.js',
		'*.js'
	]
};


<|start_filename|>controllers/projects/edit.js<|end_filename|>
'use strict';

module.exports = function(app) {

	app.use('/projects/edit/:id', app.middleware.requireAuthentication);

	app.get('/projects/edit/:id', function(req, res) {

		app.db('projects')
			.innerJoin('project_addresses','projects.id','project_addresses.project_id')
			.where({'projects.id': req.params.id })
			.select('name','description','goal_amount','token')
			.then(function(result) {
				if (!result || !result[0]) {
					res.send("We couldn't find a project with such id");
				}

				res.render('projects-edit',{
					id : req.params.id,
					name : result[0].name, 
					description : result[0].description,
					amount : result[0].goal_amount,
					token : result[0].token
				});
			});	
	});

	app.post('/projects/edit/:id', function(req, res) {

		app.db.transaction(function(trx){
			app.db('projects')
			.transacting(trx)
			.where({'projects.id': req.params.id})
			.update({
				name : req.body.name,
				description : req.body.description,
				goal_amount : req.body.amount,
			})
			.then(function(result){
				app.db('project_addresses')
				.where({'project_addresses.project_id': req.params.id})
				.update({
					token : req.body.token
				}).then(function(result) {
					res.redirect('/');
				});
			})
			.then(trx.commit)
			.catch(trx.rollback)
			.catch(function(error) {
				console.log(error);
			});
		});
	});
};


<|start_filename|>middleware/current_user.js<|end_filename|>
'use strict';

module.exports = function(app) {
	app.use(function(req, res, next) {
		res.locals.user = req.session.user;
		next();
	});
}


<|start_filename|>controllers/login.js<|end_filename|>
'use strict';

var bcrypt = require('bcrypt-nodejs');

module.exports = function(app) {

	app.get('/login', function(req, res, next) {

		if (req.isAuthenticated()) {
			res.redirect('/');
		} else {
			res.render('login');
		}
	});

	app.post('/login', function(req, res) {

		// the following variables take the
		// data username and password from the form
		var usernameReq = req.body.username;
		var passwordReq = req.body.password;
		// knex compares the information from the form
		// with the information in the user table
		// and login the user if it is right
		app.db('users')
			.where({username: usernameReq })
				.select('password')
				.then(function(result) {
					if (!result || !result[0]) { // not found
						res.send('Wrong username!');
					}
					var hash = result[0].password;
					if (bcrypt.compareSync(passwordReq, hash)) {
						// Correct username+password.
						// Generate a new session and store their user information in the session data.
						req.session.regenerate(function() {

							req.session.user = {username: usernameReq};
							res.redirect('/')
						})
					} else {
						// Wrong username/password.
						res.send('Wrong username/password!');
					}
				}).catch(function(error) {
					console.log(error);
				}); // closing then(
	});
};


<|start_filename|>controllers/projects/add.js<|end_filename|>
'use strict'

module.exports = function(app) {

	app.get('/projects/add', app.middleware.requireAuthentication, function(req, res) {
		res.render('projects-add');
	});

	app.post('/projects/add', app.middleware.requireAuthentication, function(req, res) {
		app.db.transaction(function(trx) {
			app.db('projects')
			.transacting(trx)
			.insert({
				name : req.body.name,
				description : req.body.description,
				goal_amount : req.body.amount,
			})
			.then(function(result){
				app.db('project_addresses')
				.insert({
					project_id : result,
					token : req.body.token
				}).then(function(result) {
					res.redirect('/');
				});
			})
			.then(trx.commit)
			.catch(trx.rollback)
			.catch(function(error) {
				console.log(error);
			});
		});
	});
};


<|start_filename|>views/partials/header.html<|end_filename|>
<div class='header'>
  <p>
    {{#if user}}
      Logged in as <a href="/profile">{{user.username}}</a>
      |
      <a href="/projects/add">Add new project</a>
      |
      <a href="/logout">Logout</a>
    {{else}}
      <a href="/login">Login</a>
    {{/if}}
  </p>
</div>


<|start_filename|>test/unit/services/bitcoin.js<|end_filename|>
'use strict';

var bitcoin = require('../../../services/bitcoin');
var expect = require('chai').expect;

describe('testing bitcoin.js', function() {

	it('testing function getFunds for 3 addresses', function(done) {

		var testAddresses = [
			'<KEY>',
			'<KEY>',
			'<KEY>'
		];

		// bitcoin.getFunds makes a request to a remote service.
		// This service is slow to respond sometimes.
		this.timeout(30000);

		bitcoin.getFunds(testAddresses, function(amount) {
			expect(amount).to.not.be.undefined;
			expect(amount).to.be.a('number');
			done();
		});
	});
});


<|start_filename|>grunt/env.js<|end_filename|>
'use strict';

module.exports = {
	test: {
		NODE_ENV: 'test',
		BITSTARTER_DB_HOST: '127.0.0.1',
		BITSTARTER_DB_PORT: 3306,
		BITSTARTER_DB_USER: 'bitstarter_test',
		BITSTARTER_DB_PASS: 'password',
		BITSTARTER_DB_NAME: 'bitstarter_test'
	}
};


<|start_filename|>database.js<|end_filename|>
'use strict';

var async = require('async');
var config = require('./config');

var db = module.exports = require('knex')({
	client: 'mysql',
	connection: config.db
});

db.models = require('./models');

db.setUp = function(cb) {

	async.eachSeries(db.models, function(model, next) {
		model.setUpTable(next);
	}, cb);
};


<|start_filename|>controllers/profile.js<|end_filename|>
'use strict';

var bcrypt = require('bcrypt-nodejs');

module.exports = function(app) {

	app.use('/profile', app.middleware.requireAuthentication);

	app.get('/profile', function(req, res, next) {

		var sessionUser= req.session.user.username;

		app.db('users')
			.where({username: sessionUser })
			.select('email')
			.then(function(result) {
				if (!result || !result[0]) {
					res.send("We couldn't find a user with this email");
				}

				res.render('profile', {email:result[0].email});
			});
	});

	app.post('/profile', function(req, res) {

		var usernameReq = req.body.username;
		var passwordReq = req.body.password;
		var emailReq = req.body.email;

		app.db('users')
			.where({username: usernameReq })
			.select('password')
			.then(function(result) {
				if (!result || !result[0]) {
					res.send("We couldn't find a user with this email");
				}

				var hash = result[0].password;
				bcrypt.compare(passwordReq, hash, function(err,result) {
					if (result) {
						app.db('users')
							.where({username: usernameReq })
							.update({email:emailReq})
							.then(function(count) {
								if (count == 1) {
									res.render('profile', {
										email:    emailReq,
										msg:      'Congratulations - profile for ' + usernameReq + ' updated!'
									});
								} else {
									res.render('profile', { 
										email:    emailReq,
										msg:      'failed to update profile for ' + usernameReq 
									});
								}
							});
					} else {
						res.render('profile', {
							email: emailReq,
							msg: 'Wrong password'
						});
					}
				});
			}).catch(function(error) {
				console.log(error);
			}); 
	});
};


<|start_filename|>.eslintrc.js<|end_filename|>
module.exports = {
  'extends': 'eslint:recommended',
  'rules': {
    'indent': ['error', 'tab', { 'SwitchCase': 1 }],
    'no-console': 0,
    'no-undef': 0,
    'no-unused-vars': ['error', { 'vars': 'all', 'args': 'none' }]
  }
};

<|start_filename|>middleware/static.js<|end_filename|>
'use strict';

module.exports = function(app) {

	var serveStatic = require('serve-static');

	app.use(serveStatic(__dirname + '/../public'));
};


<|start_filename|>test/integration/controllers/projects/add.js<|end_filename|>
'use strict';
var chai = require('chai');
var chaiHttp = require('chai-http');
var expect = require('chai').expect;
chai.use(chaiHttp);

var manager = require('../../../manager');


describe('testing projects.js', function() {

	before(function(done){
		manager.setUp(done)
	})

	before(function(done){
		manager.createUser('Testuser', '<EMAIL>', 'password', done)
	})

	after(manager.tearDown);

	it('add a project', function(done){

		var agent = chai.request.agent('http://localhost:3000')
		agent
			.post('/login')
			.set('content-type', 'application/x-www-form-urlencoded')
			.send({
				username : 'Testuser',
				password : 'password'
			})
			.then(function(res) {
				// The `agent` now has the sessionid cookie saved, and will send it
				// back to the server in the next request:
				return agent.post('/projects/add')
				.set('content-type', 'application/x-www-form-urlencoded')
				.set({
					name : 'test',
					description : 'test',
					amount : '12345678.12345678',
					token : '<KEY>'
				})
				.then(function(res){
					expect(res).to.have.status(200);
					expect(res.body).to.be.a('object');
					expect(res).to.redirectTo('http://localhost:3000/');
					done();
				})
			})
			.catch(done)
	})

}); // closing describe testing projects.js


<|start_filename|>middleware/auth.js<|end_filename|>
'use strict'

module.exports = function(app) {

	app.use(function(req, res, next) {

		req.isAuthenticated = function() {
			return !!req.session.user;
		};

		next();
	});

	app.middleware.requireAuthentication = function(req, res, next) {

		if (!req.isAuthenticated()) {
			return res.redirect('/login');
		}

		// The user is logged in.
		// Allow their request to continue.
		next();
	};
};


<|start_filename|>middleware/logging.js<|end_filename|>
'use strict';

module.exports = function(app) {

	app.use(function(req, res, next) {
		console.log('URL requested', req.originalUrl);
		next();
	});
};


<|start_filename|>test/manager.js<|end_filename|>
'use strict';

if (process.env.NODE_ENV !== 'test') {
	throw new Error('NODE_ENV must be set to "test" to run tests');
}

var _ = require('underscore');
var async = require('async');
var bcrypt = require('bcrypt-nodejs');

var app = require('../index');
var db = app.db;

var manager = module.exports = {

	// Wait for the app to be ready.
	onReady: function(cb) {

		if (app.ready) {
			// App is already ready.
			// Execute the callback at the next loop.
			return _.defer(cb);
		}

		// App not ready yet.
		// Wait a little time and then check again.
		setTimeout(function() {
			manager.onReady(cb);
		}, 50);
	},

	setUp: function(cb) {

		async.series([
			manager.onReady,
			manager.tearDown,
			db.setUp
		], cb);
	},

	tearDown: function(cb) {

		manager.dropDatabaseTables(cb);
	},

	dropDatabaseTables: function(cb) {

		// Drop tables in reverse order (because of foreign keys).
		var models = _.values(db.models).reverse();
		async.eachSeries(models, function(model, next) {
			db.schema.dropTableIfExists(model.tableName).then(function() {
				next();
			}).catch(next);
		}, cb);
	},

	createUser : function(username, email, password, cb){
		// Create new user to test add project and login functionality
		var rounds = 1;
		bcrypt.genSalt(rounds, function(err, salt) {
			bcrypt.hash(password, salt, null/* progress callback */, function(err, hash) {
				// store new user in db
				db('users')
					.insert({
						username: username,
						email: email,
						password: <PASSWORD>
					})
					.then(function(){
						cb();
					})
					.catch(cb);
			});
		});
	}
};


<|start_filename|>models/index.js<|end_filename|>
'use strict';

module.exports = {
	Projects: require('./Projects'),
	ProjectAddresses: require('./ProjectAddresses'),
	Users: require('./Users'),
};


<|start_filename|>index.js<|end_filename|>
'use strict';

var express = require('express');
var app = module.exports = express();

app.config = require('./config');
app.db = require('./database');
app.services = require('./services');
require('./middleware')(app);
require('./controllers')(app);

app.db.setUp(function(error) {

	if (error) {
		throw error;
	}

	// This is where we catch express errors. No "app.use" beyond this one!
	app.use(function(error, req, res, next) {
		console.error(error.stack)
		res.status(500).send('Oops! Something went wrong.')
	});

	app.listen(3000, function() {
		console.log('Example app listening on port 3000!');
	});

	app.ready = true;
});
