////
//// Fixer functions
////
// "Fixer" functions are used to transform entity attributes to fix
// user mistakes. For example, trailing whitespace and consecutive whitespace
// is usually a mistake. We don't want to trigger validation errors just because
// a user typed "foo " instead of "foo", and it would be silly to force user
// to remove the trailing space when we can do it for them.
// - Returns updated attrs.
// - "Fix" data before passing it into a validator function.

////
//// Validator functions
////
// Validator functions take an `attrs` object and may potentially be a generator
//   if they need to do anything async (like db access)
// Validator should return the fixed attrs so it's ready for db insertion.

var _ = require('lodash');
var assert = require('better-assert');
var db = require('./db');

// Util ////////////////////////////////////////////////////

// Collapses 2+ spaces into 1
// Ex: 'a   b   c' -> 'a b c'
function collapseSpaces(str) {
  return str.replace(/\s{2,}/g, ' ');
}

// Removes any whitespace in the string
function removeWhitespace(str) {
  return str.replace(/\s/g, '');
}

////////////////////////////////////////////////////////////

exports.fixNewUser = function(attrs) {
  // Prefix/suffix whitespace in usernames are accidental,
  // but inner whitespace probably isn't, so leave inner whitespace
  // intact so user can see that spaces aren't allowed
  attrs.uname = attrs.uname && attrs.uname.trim();
  // Whitespace in emails are accidental
  attrs.email = attrs.email && removeWhitespace(attrs.email);
  return attrs;
};

exports.validateNewUser = function*(attrs) {
  attrs = exports.fixNewUser(attrs);
  if (! attrs.uname)
    throw 'Username is required';
  if (! /^[a-z0-9_]+$/i.test(attrs.uname))
    throw 'Username contains invalid characters';
  // Ensure underscores are only used as separators, not anything fancier.
  if (/[_]{2,}/i.test(attrs.uname))
    throw 'Username contains consecutive underscores';
  if (/^[_]|[_]$/i.test(attrs.uname))
    throw 'Username starts or ends with underscores';
  if (attrs.uname.length < 2 || attrs.uname.length > 15)
    throw 'Username must be 2-15 characters';
  if (! attrs.password1)
    throw 'Password is required';
  if (attrs.password1.length < 6)
    throw 'Password must be 6 or more characters';
  if (attrs.password1 !== attrs.password2)
    throw 'Password confirmation does not match';

  // Case-insensitive comparison. If 'ace' exists, we don't allow 'Ace'
  if (yield db.findUserByUname(attrs.uname)) {
    throw 'Username is taken';
  };

  // Validation checks out, so return the fixed attrs
  return attrs;
};

@@ -726,16 +726,29 @@
 rtion.%0A%0A
+// 3rd party%0A
 var _ = 
@@ -801,24 +801,85 @@
 r-assert');%0A
+var debug = require('debug')('app:validation');%0A// 1st party%0A
 var db = req
@@ -2240,24 +2240,101 @@
 haracters';%0A
+  if (!attrs.email %7C%7C attrs.email.length %3C 3)%0A    throw 'Email is required';%0A
   if (! attr
@@ -2715,16 +2715,97 @@
 ;%0A  %7D;%0A%0A
+  if (yield db.findUserByEmail(attrs.email)) %7B%0A    throw 'Email is taken';%0A  %7D;%0A%0A
   // Val

Check email-uniqueness in validator function