Browse files

Style consistency; less noisy tests; new default make task.

* Style consistency: everything now passes jshint.
* Less noisy tests: lib/logger.js provides dummy methods if NODE_ENV=test
* New default `make` task: now lints and runs the tests.
  • Loading branch information...
1 parent 777daf6 commit 85ec0a9767ec25b56b94a31decf53750a89933ad @brianloveswords committed Apr 30, 2012
Showing with 251 additions and 216 deletions.
  1. +1 −0 .jshintrc
  2. +1 −1 .puppet-manifests/openbadges.pp
  3. +7 −0 Makefile
  4. +64 −64 controllers/issuer.js
  5. +4 −4 lib/configuration.js
  6. +11 −11 lib/hogan-express.js
  7. +5 −0 lib/logging.js
  8. +34 −29 lib/mysql.js
  9. +2 −2 lib/regex.js
  10. +42 −36 lib/router.js
  11. +9 −10 lib/secrets.js
  12. +8 −7 models/user.js
  13. +2 −1 package.json
  14. +61 −51 run.js
View
1 .jshintrc
@@ -7,5 +7,6 @@
"laxbreak": true,
"noarg": true,
"undef": true,
+ "proto": true,
"lastsemic": true
}
View
2 .puppet-manifests/openbadges.pp
@@ -29,7 +29,7 @@
}
npm { "vows": }
-
+ npm { "jshint": }
npm { "up": }
file { "package.json":
View
7 Makefile
@@ -2,6 +2,13 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# we don't want to try to install the npm packages
+all: lint
+ npm test
+
+lint:
+ jshint middleware.js lib/*.js models/*.js controllers/*.js
+
clean:
rm -rf node_modules rpmbuild *.rpm *.tar.gz
View
128 controllers/issuer.js
@@ -17,7 +17,7 @@ var regex = require('../lib/regex.js');
* @return {String} a fully qualified url, using parts from the origin if
* the original `pathOrUrl` was just a path.
*/
-function qualifyUrl (pathOrUrl, origin) {
+function qualifyUrl(pathOrUrl, origin) {
var parts = url.parse(pathOrUrl);
if (!parts.hostname) {
var originParts = url.parse(origin);
@@ -31,23 +31,23 @@ function qualifyUrl (pathOrUrl, origin) {
}
var myFiles = [
- "issuer-parts/issuer-script-intro.js"
-, "jquery.min.js"
-, "jschannel.js"
-, "issuer-parts/issuer-core.js"
-, "issuer-parts/issuer-script-outro.js"
+ "issuer-parts/issuer-script-intro.js",
+ "jquery.min.js",
+ "jschannel.js",
+ "issuer-parts/issuer-core.js",
+ "issuer-parts/issuer-script-outro.js"
];
-myFiles = myFiles.map(function(filename) {
+myFiles = myFiles.map(function (filename) {
return __dirname + '/../static/js/' + filename;
});
function concatenate(files, cb) {
var completed = 0;
var contents = [];
-
+
function startLoading(i) {
- fs.readFile(files[i], function(err, data) {
+ fs.readFile(files[i], function (err, data) {
if (err) {
cb(err);
return;
@@ -61,10 +61,10 @@ function concatenate(files, cb) {
for (var i = 0; i < files.length; i++)
startLoading(i);
-};
+}
if (module.parent === null) {
- concatenate(myFiles, function(err, data) {
+ concatenate(myFiles, function (err, data) {
var filename = 'issuer.js';
if (err)
throw err;
@@ -73,8 +73,8 @@ if (module.parent === null) {
});
}
-exports.generateScript = function(req, res) {
- concatenate(myFiles, function(err, data) {
+exports.generateScript = function (req, res) {
+ concatenate(myFiles, function (err, data) {
if (err) {
res.send(500);
throw err;
@@ -85,7 +85,7 @@ exports.generateScript = function(req, res) {
});
};
-exports.frame = function(req, res) {
+exports.frame = function (req, res) {
res.render('issuer-frame', {
layout: null,
csrfToken: req.session._csrf,
@@ -94,38 +94,38 @@ exports.frame = function(req, res) {
};
-exports.issuerBadgeAddFromAssertion = function(req, res, next) {
+exports.issuerBadgeAddFromAssertion = function (req, res, next) {
/* the issuer api, flawed in that it needs to query to badge assertion
* so that we're not making a double request to the issuer, once for the GET
* confirming the badge, and once for the POST awarding the badge. Not
* sure what caching options we have currently, so just going ahead and
* making a double request.
- *
+ *
* request can either be a GET or a POST, one required param 'url'
* which points to a badge assertion.
- *
+ *
*/
logger.debug("here's my full url " + req.originalUrl);
- var user = req.user
- var error = req.flash('error')
+ var user = req.user;
+ var error = req.flash('error');
var success = req.flash('success');
// is the user logged in? if not, suggest they redirect to the login page
- if (!user) return res.json({message:"user is not logged in, redirect to " + reverse('backpack.login'),
- redirect_to: reverse('backpack.login')}, 403);
+ if (!user) return res.json({ message: "user is not logged in, redirect to " + reverse('backpack.login'),
+ redirect_to: reverse('backpack.login') }, 403);
// get the url param (lots of debugging statements here)
var assertionUrl = req.query.url; // if it was as a query param in the GET
if (!assertionUrl) {
- logger.debug("I'm doing a " + req.method);
+ logger.debug("I'm doing a " + req.method);
logger.debug("tried GET assertionUrl, didn't get anything " + req.param());
logger.debug("full query " + JSON.stringify(req.query));
// if the param was in a POST body
assertionUrl = req.body['url'];
logger.debug("POST attempt got " + assertionUrl);
// more debugging
- if (!assertionUrl && req.method=='GET') {
+ if (!assertionUrl && req.method == 'GET') {
logger.debug("GET is erroring this was the original url " + req.originalUrl);
logger.debug(JSON.stringify(req.body));
}
@@ -148,51 +148,52 @@ exports.issuerBadgeAddFromAssertion = function(req, res, next) {
}
}
- /* grabbing the remote assertion, 3 nested steps -
- *
+ /* grabbing the remote assertion, 3 nested steps -
+ *
* 1) grab the remote assertion
* 2) grab the remote badge image
- * if the request is a POST
+ * if the request is a POST
* 3) award the badge
*/
- remote.getHostedAssertion(assertionUrl, function(err, assertion) {
+ remote.getHostedAssertion(assertionUrl, function (err, assertion) {
var recipient = user.get('email');
if (err || !assertion) {
var error_msg = "trying to grab url " + assertionUrl + " got error " + err;
logger.error(error_msg);
- return res.json({ message: error_msg }, 502) ;
+ return res.json({ message: error_msg }, 502);
}
-
+
var userOwnsBadge = Badge.confirmRecipient(assertion, recipient);
if (req.method == 'POST' && !userOwnsBadge) {
return res.json({ message: "badge assertion is for a different user" }, 403);
}
-
+
// #TODO: write tests for invalid assertions, potentially move this check
// into remote.getHostedAssertion?
// Badge.validateBody is ill named -- it returns null if the badge is
// valid, an error object if the badge is not valid.
if (Badge.validateBody(assertion)) {
return res.json({ message: "badge assertion appears to be invalid" }, 400);
- }
-
+ }
+
// grabbing the remote badge image
var imageUrl = qualifyUrl(assertion.badge.image, assertion.badge.issuer.origin);
- remote.badgeImage(imageUrl, function(err, imagedata) {
- if (err){
+ remote.badgeImage(imageUrl, function (err, imagedata) {
+ if (err) {
var error_msg = "trying to grab image at url " + imageUrl + " got error " + err;
logger.error(error_msg);
return res.json({ message: error_msg }, 502);
}
// awarding the badge, only done if this is a POST
- if (req.method=='POST') {
+ if (req.method == 'POST') {
var opts = {
assertion: assertion,
url: assertionUrl,
imagedata: imagedata,
recipient: recipient
- }
- awardBadge(opts, function(err, badge) {
+ };
+
+ awardBadge(opts, function (err, badge) {
if (err) {
var error_message = "badge error " + assertionUrl + err;
logger.error(error_message);
@@ -207,28 +208,27 @@ exports.issuerBadgeAddFromAssertion = function(req, res, next) {
return res.json({badge: assertion, exists: false, 'message': error_message}, 500);
}
logger.debug("badge added " + assertionUrl);
-
- return res.json({exists: false, badge:assertion}, 201);
+ return res.json({exists: false, badge: assertion}, 201);
});
}
-
+
// if this is a GET, we still need to return the badge
else {
- assertion.badge.image = imageUrl;
-
+ assertion.badge.image = imageUrl;
+
var response = {exists: false, badge: assertion, recipient: recipient};
- Badge.findOne({endpoint: assertionUrl}, function(err, badge) {
+ Badge.findOne({endpoint: assertionUrl}, function (err, badge) {
if (err) {
logger.error(err);
return res.json({message: "internal server error"}, 500);
}
-
+
if (badge && badge.get("user_id") == req.user.get("id"))
response.exists = true;
-
+
if (Badge.confirmRecipient(assertion, req.user.get('email')))
response.owner = true;
-
+
return res.json(response, 200);
});
}
@@ -237,42 +237,42 @@ exports.issuerBadgeAddFromAssertion = function(req, res, next) {
};
exports.validator = function (request, response) {
- var assertion = request.query.assertion || (request.body && request.body.assertion)
+ var assertion = request.query.assertion || (request.body && request.body.assertion);
var accept = request.headers['accept'];
var missingMsg = 'error: could not validate, could not find assertion in `data` field';
var status = 200;
var fields = {};
-
+
if (!assertion) {
status = 400;
fields = { general: missingMsg };
}
else {
try {
status = 200;
- var o = JSON.parse(assertion);
- if (!o.badge) o.badge = {}
- if (!o.badge.issuer) o.badge.issuer = {}
- var errors = Badge.validateBody( o );
+ var assertionObject = JSON.parse(assertion);
+ if (!assertionObject.badge) assertionObject.badge = {};
+ if (!assertionObject.badge.issuer) assertionObject.badge.issuer = {};
+ var errors = Badge.validateBody(assertionObject);
if (errors) {
fields = errors.fields;
status = 400;
}
}
-
+
catch (err) {
status = 500;
if (err.name === "SyntaxError") {
- fields = { general: "Could not parse this JSON blob. Make sure it is well formed and try again!" }
+ fields = { general: "Could not parse this JSON blob. Make sure it is well formed and try again!" };
} else {
- fields = { general: err.name + ": " + err.message }
+ fields = { general: err.name + ": " + err.message };
}
}
}
-
- function humanize (value, field) {
+
+ function humanize(value, field) {
var url = 'Must either be a fully qualified URL (<code>http://example.com/path/evidence.html</code>) or begin with a forward slash (<code>/path/evidence.html</code>). <br> Non-qualified URLs will be prefixed with the origin specified in <code>badge.issuer.origin</code>';
- var length = 'Cannot be longer than 128 characters'
+ var length = 'Cannot be longer than 128 characters';
var msgs = {
recipient: 'Must be an email address (<code>someone@example.com</code>) or a hash (<code>sha256$1234567890abcdef</code>)',
evidence: url,
@@ -285,24 +285,24 @@ exports.validator = function (request, response) {
"badge.issuer.org": length,
"badge.issuer.contact": 'Must be an email address',
"badge.issuer.origin": 'Must be a fully qualified origin (<code>http://example.com</code>)'
- }
+ };
if (value.match(/invalid/)) value = msgs[field] || value;
return {field: field, value: value};
}
-
- var responder = {
+
+ var responder = {
'text/plain': function () {
response.contentType('txt');
if (!_.isEmpty(fields)) {
var values = _.values(fields);
- var bullets = _.map(values, function(s){return '* ' + s;}).join('\n');
+ var bullets = _.map(values, function (s) { return '* ' + s; }).join('\n');
return response.send(bullets, status);
}
else {
return response.send('everything looks good', 200);
}
},
-
+
'application/json': function () {
response.contentType('json');
if (fields) {
@@ -312,7 +312,7 @@ exports.validator = function (request, response) {
return response.json({ status: 'okay' }, 200);
}
},
-
+
'default': function () {
var fielderrors = _.map(fields, humanize);
return response.render('validator', {
View
8 lib/configuration.js
@@ -1,5 +1,5 @@
var config = {};
-exports.get = function(val, env) {
+exports.get = function (val, env) {
env = env || process.env['NODE_ENV'];
if (val === 'env') return env;
if (!config[env]) {
@@ -10,10 +10,10 @@ exports.get = function(val, env) {
}
config[env] = require(path).config;
}
- return config[env][val]
-}
+ return config[env][val];
+};
-function exists (file) {
+function exists(file) {
try {
require(file);
return true;
View
22 lib/hogan-express.js
@@ -1,18 +1,18 @@
// from http://allampersandall.blogspot.com/2011/12/hoganjs-expressjs-nodejs.html
-var HoganExpressAdapter=(function(){
- var init=function(hogan) {
- var compile=function(source){
- return function(options) {
+var HoganExpressAdapter = (function () {
+ var init = function (hogan) {
+ var compile = function (source) {
+ return function (options) {
return hogan.compile(source).render(options);
};
- }
- return {compile:compile};
+ };
+ return { compile: compile };
};
- return {init:init};
+ return { init: init };
}());
-if(typeof module!== 'undefined' && module.exports){
- module.exports=HoganExpressAdapter;
-} else if (typeof exports!=='undefined') {
- exports.HoganExpressAdapter=HoganExpressAdapter;
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = HoganExpressAdapter;
+} else if (typeof exports !== 'undefined') {
+ exports.HoganExpressAdapter = HoganExpressAdapter;
}
View
5 lib/logging.js
@@ -80,3 +80,8 @@ exports.logger.add(winston.transports.Console, {
colorize: true,
timestamp: true
});
+
+function nope() {}
+if (process.env['NODE_ENV'] === 'test') {
+ exports.logger = { debug: nope, error: nope, warn: nope, info: nope };
+}
View
63 lib/mysql.js
@@ -1,7 +1,7 @@
-var mysql = require('mysql')
- , conf = require('../lib/configuration').get('database')
- , client = mysql.createClient(conf)
- , testDb = "`test_" + conf.database + "`";
+var mysql = require('mysql');
+var conf = require('../lib/configuration').get('database');
+var client = mysql.createClient(conf);
+var testDb = "`test_" + conf.database + "`";
var dbEncoding = 'utf8';
@@ -26,10 +26,10 @@ var schemas = [
+ "rejected BOOLEAN DEFAULT 0,"
+ "body MEDIUMBLOB NOT NULL,"
+ "body_hash VARCHAR(255) UNIQUE NOT NULL,"
- + "validated_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
+ + "validated_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
+ "FOREIGN KEY user_fkey (user_id) REFERENCES `user`(id)"
+ ") ENGINE=InnoDB;",
-
+
"CREATE TABLE IF NOT EXISTS `group` ("
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY,"
+ "user_id BIGINT NOT NULL,"
@@ -39,7 +39,7 @@ var schemas = [
+ "badges MEDIUMBLOB NOT NULL,"
+ "FOREIGN KEY user_fkey (user_id) REFERENCES `user`(id)"
+ ") ENGINE=InnoDB;",
-
+
"CREATE TABLE IF NOT EXISTS `portfolio` ("
+ "`id` bigint AUTO_INCREMENT PRIMARY KEY,"
+ "`group_id` bigint NOT NULL,"
@@ -55,47 +55,52 @@ var schemas = [
exports.schemas = schemas;
exports.createTables = function () {
- schemas.forEach(function(schema){
+ schemas.forEach(function (schema) {
client.query(schema);
- })
-}
+ });
+};
+
exports.useTestDatabase = function () {
client.query("CREATE DATABASE IF NOT EXISTS " + testDb + " CHARACTER SET '" + dbEncoding + "'");
- client.query("USE "+ testDb);
-}
+ client.query("USE " + testDb);
+};
+
exports.dropTestDatabase = function () {
client.query("DROP DATABASE IF EXISTS " + testDb);
-}
+};
+
exports.prepareTesting = function () {
exports.dropTestDatabase();
exports.useTestDatabase();
exports.createTables();
-}
+};
+
+exports.client = client;
-exports.client = client
client._insert = function (table, fields, callback) {
- var keys = Object.keys(fields)
- , values = keys.map(function (k) { return fields[k] })
- , placeholders = keys.map(function () { return '?' });
+ var keys = Object.keys(fields);
+ var values = keys.map(function (k) { return fields[k] });
+ var placeholders = keys.map(function () { return '?' });
var querystring
- = 'INSERT INTO `'+table+'` '
- + '('+keys.join(', ')+') '
+ = 'INSERT INTO `' + table + '` '
+ + '(' + keys.join(', ') + ') '
+ 'VALUES '
- + '('+placeholders.join(', ')+')';
+ + '(' + placeholders.join(', ') + ')';
client.query(querystring, values, callback);
-}
+};
client._upsert = function (table, fields, callback) {
if (!fields['id']) return client._insert(table, fields, callback);
- var keys = Object.keys(fields)
- , values = keys.map(function (k) { return fields[k] })
+ var keys = Object.keys(fields);
+ var values = keys.map(function (k) { return fields[k] });
var querystring
- = 'UPDATE `'+table+'` SET '
+ = 'UPDATE `' + table + '` SET '
+ keys.map(function (k) { return k + ' = ?'}).join(', ')
- + ' WHERE id = ?'
+ + ' WHERE id = ?';
values.push(fields['id']);
- client.query(querystring, values, callback)
-}
-exports.createTables()
+ client.query(querystring, values, callback);
+};
+
+exports.createTables();
View
4 lib/regex.js
@@ -1,6 +1,6 @@
exports.url = /(^(https?):\/\/[^\s\/$.?#].[^\s]*$)|(^\/\S+$)/;
-exports.email = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
+exports.email = /[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+)*@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?/;
exports.origin = /^(https?):\/\/[^\s\/$.?#].[^\s\/]*\/?$/;
exports.version = /^v?\d+\.\d+(\.\d+)?$/;
exports.date = /(^\d{4}-\d{2}-\d{2}$)|(^\d{1,10}$)/;
-exports.emailOrHash = /([a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)|((sha1|sha256|sha512|md5)\$[a-fA-F0-9]+)/;
+exports.emailOrHash = /([a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+)*@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?)|((sha1|sha256|sha512|md5)\$[a-fA-F0-9]+)/;
View
78 lib/router.js
@@ -1,77 +1,83 @@
// Helper library for path routing in express and allowing reverse path
// lookup. See ../app.js for example of its usage
-//
+//
// This is currently written in such a way that it cannot be easily included
// in more than one app where the paths might overlap. `defroutes` is used to
// do the reverse lookup and it's set at a global level, rather than
// per-router instance.
-var path = require('path')
- , defroutes = {}
+var path = require('path');
+var defroutes = {};
-var router = module.exports = function(app){
+var router = module.exports = function (app) {
if (!(this instanceof router)) return new router(app);
this.app = app;
this.loaded = [];
-}
+};
+
// Generator for creating router methods.
// Router methods take a route and a controller path in the format
// `filename`.`methodname`. Currently the controllers must live in
// <app_root>/controllers
-router._method = function(type) {
- return function(route, cPath){
- this._saveRoute(cPath, route)
+router._method = function (type) {
+ return function (route, cPath) {
+ this._saveRoute(cPath, route);
this.app[type](route, this._endpoint(cPath));
return this;
- }
-}
-router.prototype.get = router._method('get');
-router.prototype.post = router._method('post');
-router.prototype.put = router._method('put');
-router.prototype.delete = router._method('delete');
+ };
+};
+
+router.prototype['get'] = router._method('get');
+router.prototype['post'] = router._method('post');
+router.prototype['put'] = router._method('put');
+router.prototype['delete'] = router._method('delete');
// Finds an endpoint (method to handle a path) from a controller path
// (filename.methodname). See router.prototype._load
-router.prototype._endpoint = function(cPath) {
- var ref = cPath.split('.')
- , controller = ref[0]
- , method = ref[1]
+router.prototype._endpoint = function (cPath) {
+ var ref = cPath.split('.');
+ var controller = ref[0];
+ var method = ref[1];
return this._load(controller)[method];
-}
+};
+
// Loads a controller file and checks to see if any params need to be
// registered, registers them with router.prototype._applyParam
-router.prototype._load = function(file){
- var controller = require(path.join('../controllers', file))
+router.prototype._load = function (file) {
+ var controller = require(path.join('../controllers', file));
if (this.loaded.indexOf(file) === -1) {
this.loaded.push(file);
this._applyParam(controller.param);
}
return controller;
-}
+};
+
// Checks the controller file for an exports.param object, applies all of the
// param preprocessors it finds to the app. See docs for express for more
// information on param preprocessing.
-router.prototype._applyParam = function(param){
+router.prototype._applyParam = function (param) {
var app = this.app;
param = param || {};
- Object.keys(param).forEach(function(k){
+ Object.keys(param).forEach(function (k) {
app.param(k, param[k]);
- })
-}
+ });
+};
+
// Saves the route to the (global) defroutes object so we can lookup later.
-router.prototype._saveRoute = function(cPath, route) {
- defroutes[cPath] = defroutes[cPath] || []
+router.prototype._saveRoute = function (cPath, route) {
+ defroutes[cPath] = defroutes[cPath] || [];
defroutes[cPath].push(route);
return route;
-}
+};
+
// Look up a route from the defroutes table. Can also take a hash of
// parameters and values to substitute in the route if necessary.
-router.reverse = function(cPath, params){
+router.reverse = function (cPath, params) {
//need to add the ability to break up cPath into params and then eval th params - not sure if that's a good
//security thing to do though. - the params would be a json-able thing though, right?
- var route = (defroutes[cPath] || [])[0]
- if (!route) throw new Error('Controller "'+ cPath +'" is not bound to a route')
- Object.keys((params || {})).forEach(function(key){
+ var route = (defroutes[cPath] || [])[0];
+ if (!route) throw new Error('Controller "' + cPath + '" is not bound to a route');
+ Object.keys((params || {})).forEach(function (key) {
route = route.replace(':' + key, params[key]);
- })
- return route
-}
+ });
+ return route;
+};
View
19 lib/secrets.js
@@ -33,25 +33,24 @@
*
* ***** END LICENSE BLOCK ***** */
-const
-path = require('path'),
-fs = require('fs');
+var path = require('path');
+var fs = require('fs');
-exports.generate = function(chars) {
+exports.generate = function (chars) {
var str = "";
- const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- for (var i=0; i < chars; i++) {
+ var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ for (var i = 0; i < chars; i++) {
str += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
}
return str;
-}
+};
-exports.hydrateSecret = function(name, dir) {
+exports.hydrateSecret = function (name, dir) {
var p = path.join(dir, name + ".sekret");
var fileExists = false;
- var secret = undefined;
+ var secret;
- try{ secret = fs.readFileSync(p).toString(); } catch(e) {};
+ try { secret = fs.readFileSync(p).toString(); } catch (e) {}
if (secret === undefined) {
secret = exports.generate(128);
View
15 models/user.js
@@ -6,24 +6,25 @@ var Base = require('./mysql-base');
var User = function (attributes) {
this.attributes = attributes;
this.setLoginDate = function () {
- this.set('last_login', Math.floor(Date.now()/1000));
+ this.set('last_login', Math.floor(Date.now() / 1000));
};
-}
+};
+
Base.apply(User, 'user');
User.findOrCreate = function (email, callback) {
- var newUser = new User({email: email});
- User.findOne({email: email}, function (err, user) {
+ var newUser = new User({ email: email });
+ User.findOne({ email: email }, function (err, user) {
if (err) { return callback(err); }
if (user) { return callback(null, user); }
else { return newUser.save(callback); }
- })
-}
+ });
+};
User.validators = {
email: function (value) {
if (!regex.email.test(value)) { return "invalid value for required field `email`"; }
}
-}
+};
module.exports = User;
View
3 package.json
@@ -3,7 +3,7 @@
, "version": "0.5.0"
, "private": true
, "scripts" :
- { "test" : "vows --spec --isolate" }
+ { "test" : "NODE_ENV=test vows --isolate" }
, "dependencies":
{ "api-easy": "~0.3.3"
, "colors": "*"
@@ -13,6 +13,7 @@
, "formidable": "~1.0.9"
, "functools": "~1.2.0"
, "hogan.js": "~1.0.5"
+ , "jshint": "~0.6.2"
, "metapng": "git+https://github.com/brianloveswords/metapng.js.git"
, "mime": "~1.2.5"
, "mysql": "~0.9.5"
View
112 run.js
@@ -1,24 +1,24 @@
#!/usr/bin/env node
-var spawn = require('child_process').spawn
- , colors = require('colors')
- , http = require('http')
- , program = require('commander')
- , qs = require('querystring')
+var spawn = require('child_process').spawn;
+var colors = require('colors');
+var http = require('http');
+var program = require('commander');
+var qs = require('querystring');
program
.version('0.5.0')
.option('-p, --port [port]', 'Run a webhook server on specified port')
.option('-b, --branch [branch]', 'Only watch for changes on specified branch [master]', 'master')
.option('-e, --env [env]', 'Run under specified environment')
- .parse(process.argv)
+ .parse(process.argv);
var restarts = 0;
var running_server;
-var log = function() {
+var log = function () {
console.log("runner: ".magenta + Array.prototype.slice.call(arguments).join(' '));
-}
+};
-var spawn_server = function(){
+var spawn_server = function () {
var app, fancypid;
if (++restarts > 5) {
log('too many failures, shut. down. everything.');
@@ -27,80 +27,90 @@ var spawn_server = function(){
log('spawning new server');
app = spawn('node', ['app.js']);
- fancypid = ('('+app.pid+') ').grey;
+ fancypid = ('(' + app.pid + ') ').grey;
- app.stdout.on('data', function(data){
+ app.stdout.on('data', function (data) {
process.stdout.write(fancypid);
process.stdout.write(data);
- })
- app.stderr.on('data', function(data){
+ });
+
+ app.stderr.on('data', function (data) {
process.stderr.write(fancypid);
process.stderr.write(data);
- })
- app.on('exit', function(code, sig) {
+ });
+
+ app.on('exit', function (code, sig) {
if (sig) log('server killed with signal ' + sig);
if (code) log('server exited with code ' + code);
running_server = spawn_server();
- })
+ });
return app;
-}
-var webhook_server = function(port, branch) {
- log('starting webhook server on port', port)
+};
+
+var webhook_server = function (port, branch) {
+ log('starting webhook server on port', port);
log('watching for changes on', branch, 'branch');
- http.createServer(function(req, resp){
+ http.createServer(function (req, resp) {
var commitData = '';
- req.on('data', function(incoming){ commitData += incoming; })
- req.on('end', function(){
+ req.on('data', function (incoming) { commitData += incoming });
+ req.on('end', function () {
var commit, payload;
resp.end('okay');
try {
payload = qs.parse(commitData)['payload'];
commit = JSON.parse(payload);
- } catch(e) {
+ } catch (e) {
log('ignoring illegal webhook attempt from', req.client.remoteAddress);
return;
}
if (commit.ref.match('refs/heads/' + branch)) {
- log('new deploy at ' + (new Date()).toGMTString())
- pull_new_code(function(){ running_server.kill(); })
+ log('new deploy at ' + (new Date()).toGMTString());
+ pull_new_code(function () { running_server.kill() });
}
- })
- }).listen(port);
-}
+ });
+ }).listen(port);
+};
-var pull_new_code = function(callback) {
+var pull_new_code = function (callback) {
var git = spawn('git', ['pull', 'deploy', 'master']);
- var preface = 'git '.magenta
- git.stdout.on('data', function(data){
+ var preface = 'git '.magenta;
+
+ git.stdout.on('data', function (data) {
process.stdout.write(preface);
process.stderr.write(data);
- })
- git.stderr.on('data', function(data){
+ });
+
+ git.stderr.on('data', function (data) {
process.stderr.write(preface);
process.stderr.write(data);
- })
- git.on('exit', function(code, sig){
- if (code === 0) { install_new_modules(callback); }
- })
-}
-var install_new_modules = function(callback) {
+ });
+
+ git.on('exit', function (code, sig) {
+ if (code === 0) install_new_modules(callback);
+ });
+};
+
+var install_new_modules = function (callback) {
var npm = spawn('npm', ['install']);
- var preface = 'npm '.magenta
- npm.stdout.on('data', function(data){
+ var preface = 'npm '.magenta;
+
+ npm.stdout.on('data', function (data) {
process.stdout.write(preface);
process.stderr.write(data);
- })
- npm.stderr.on('data', function(data){
+ });
+
+ npm.stderr.on('data', function (data) {
process.stderr.write(preface);
process.stderr.write(data);
- })
- npm.on('exit', function(code, sig){
+ });
+
+ npm.on('exit', function (code, sig) {
if (code === 0) { callback(); }
- })
-}
+ });
+};
-if (program.env) process.env['NODE_ENV'] = program.env
+if (program.env) process.env['NODE_ENV'] = program.env;
log('pid:', process.pid);
running_server = spawn_server();
@@ -117,8 +127,8 @@ var srs = 0;
process.on('SIGINT', function () {
if (srs) process.exit();
srs = 1;
- setTimeout(function(){srs = 0;}, 1000);
-})
+ setTimeout(function () { srs = 0 }, 1000);
+});
// reduce restart count.
-setInterval(function(){ if (restarts > 0) restarts--; }, 5000);
+setInterval(function () { if (restarts > 0) restarts--; }, 5000);

0 comments on commit 85ec0a9

Please sign in to comment.