Skip to content

Commit

Permalink
Add validation for unique project and screen titles. Fix tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Karthik Viswanathan committed Aug 13, 2012
1 parent 59d802f commit 613a738
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 89 deletions.
26 changes: 16 additions & 10 deletions lib/components.js
Expand Up @@ -23,24 +23,29 @@ function getDefaultComponent(req) {
/* Validate component
* Requires:
* req - web request,
* beingCreated - true if this component is being created for the first time
* and false otherwise
* Returns: true if the request is valid to create/update a component or an
* error message otherwise
* beingCreated - true if this component is being created for the first time and
* false otherwise,
* db - db connection
* Calls: callback([error]):
* error - if there was a validation issue, this is an error message that
* explains it; otherwise, this argument is not provided.
*/
function validateComponent(req, beingCreated) {
function validateComponent(req, beingCreated, db, callback) {
var body = req.body;
var type = body.type;
var row = body.row;
var col = body.col;
var action = body.action;

if (typeof row !== 'number' || typeof col !== 'number') {
return 'Component must have a numeric row and column.';
callback('Component must have a numeric row and column.');
return;
} else if (typeof type !== 'string') {
return 'Component must have a type.';
callback('Component must have a type.');
return;
} else if (type.length < 1 || type.length > 20) {
return 'Component must have a type between 1 and 20 characters long.';
callback('Component must have a type between 1 and 20 characters long.');
return;
}

if (action !== undefined) {
Expand All @@ -49,11 +54,12 @@ function validateComponent(req, beingCreated) {
}

if (typeof action !== 'number') {
return "Component's action must be a numeric id";
callback("Component's action must be a numeric id");
return;
}
}

return true;
callback();
}

exports = module.exports = scaffold.generate(['projects', 'screens'],
Expand Down
45 changes: 29 additions & 16 deletions lib/elements.js
Expand Up @@ -36,15 +36,18 @@ function getDefaultElement(req) {
};
}


/* Validate element
* Requires:
* req - web request,
* beingCreated - true if this element is being created for the first time
* and false otherwise
* Returns: true if the request is valid to create/update a element or an
* error message otherwise
* beingCreated - true if this element is being created for the first time and
* false otherwise,
* db - db connection
* Calls: callback([error]):
* error - if there was a validation issue, this is an error message that
* explains it; otherwise, this argument is not provided.
*/
function validateElement(req, beingCreated) {
function validateElement(req, beingCreated, db, callback) {
var body = req.body;
var type = body.type;
var nextId = body.nextId;
Expand All @@ -57,11 +60,14 @@ function validateElement(req, beingCreated) {
// TODO: Should these be on both the client and server side? If so, how
// should they be kept in sync?
if (typeof type !== 'string') {
return 'Element must have a type.';
callback('Element must have a type.');
return;
} else if (type.length < 1 || type.length > 20) {
return "Element must have a type between 1 and 20 characters long.";
callback("Element must have a type between 1 and 20 characters long.");
return;
} else if (nextId && typeof nextId !== 'number') {
return "Element's nextId must be an integer.";
callback("Element's nextId must be an integer.");
return;
}

if (required !== undefined) {
Expand All @@ -72,23 +78,28 @@ function validateElement(req, beingCreated) {
}

if (typeof required !== 'boolean') {
return "Element's required attribute must be a boolean.";
callback("Element's required attribute must be a boolean.");
return;
}
}

if (name !== undefined) {
if (typeof name !== 'string') {
return "Element's name must be a string.";
callback("Element's name must be a string.");
return;
} else if (name.length < 1 || name.length > 50) {
return "Element's name must be between 1 and 50 characters long.";
callback("Element's name must be between 1 and 50 characters long.");
return;
}
}

if (text !== undefined) {
if (typeof text !== 'string') {
return "Element's text must be a string.";
callback("Element's text must be a string.");
return;
} else if (text.length < 1 || text.length > 500) {
return "Element's text must be between 1 and 500 characters long.";
callback("Element's text must be between 1 and 500 characters long.");
return;
}
}

Expand All @@ -98,13 +109,15 @@ function validateElement(req, beingCreated) {
}

if (typeof level !== 'number') {
return "Element's level must be a number.";
callback("Element's level must be a number.");
return;
} else if (level < 1 || level > 6) {
return "Element's level must be between 1 and 6.";
callback("Element's level must be between 1 and 6.");
return;
}
}

return true;
callback();
}

exports = module.exports = scaffold.generate(['projects', 'screens',
Expand Down
33 changes: 26 additions & 7 deletions lib/projects.js
Expand Up @@ -22,19 +22,38 @@ function getDefaultProject(req) {
* Requires:
* req - web request,
* beingCreated - true if this project is being created for the first time and
* false otherwise
* Returns: true if the request is valid to create/update a project
* or an error message otherwise
* false otherwise,
* db - db connection
* Calls: callback([error]):
* error - if there was a validation issue, this is an error message that
* explains it; otherwise, this argument is not provided.
*/
function validateProject(req, beingCreated) {
function validateProject(req, beingCreated, db, callback) {
var title = req.body.title;

if (!title) {
return 'Project must have a title.';
callback('Project must have a title.');
return;
} else if (title.length < 1 || title.length > 20) {
return 'Project must have a title between 1 and 20 characters long.';
callback('Project must have a title between 1 and 20 characters long.');
return;
}
return true;

exports.list(req, db, function(err, projectList) {
if (err) {
throw err;
} else {
for (var i = 0; i < projectList.length; i++) {
if (projectList[i].title.toLowerCase() === title.toLowerCase()) {
callback('Project must have a unique case-insensitive title.');
return;
}
}

// everything has been validated; there are no errors
callback();
}
});
}

/*
Expand Down
47 changes: 24 additions & 23 deletions lib/scaffold.js
Expand Up @@ -15,11 +15,12 @@ var users = require('./users');
* a request
* allowedFields - fields that are allowed to be modified in the form of
* a map
* validateRequest - function(req, beingCreated) which determines whether the
* POST values in the given request are valid for creating or updating this
* object. beingCreated will be true if the object is being created or
* false if it is being updated. validateRequest should return true if the
* request is valid or return an error message otherwise.
* validateRequest - function(req, beingCreated, db, callback) which determines
* whether the POST values in the given request are valid for creating or
* updating this object. beingCreated will be true if the object is being
* created or false if it is being updated. validateRequest should call
* the given callback when finished with an error message as the first
* parameter if there were validation issues or no parameters otherwise
*
* Returns: the scaffold in the form of an object with the following methods:
* list(req, db, callback) - get a list of the scaffolded objects
Expand Down Expand Up @@ -254,34 +255,34 @@ exports.generate = function(parents, children, name, getDefault,

// POST should create
app.post(baseRoute, middleware, function(req, res) {
var result = validateRequest(req);
if (result !== true) {
res.send(result, 400);
return;
}

that.add(req, db, function(err, object) {
var result = validateRequest(req, true, db, function(err) {
if (err) {
throw err;
res.send(err, 400);
} else {
res.send(object);
that.add(req, db, function(err, object) {
if (err) {
throw err;
} else {
res.send(object);
}
});
}
});
});

// PUT should update
app.put(baseRoute + '/:id', middleware, function(req, res) {
var result = validateRequest(req);
if (result !== true) {
res.send(result, 400);
return;
}

that.update(req, db, req.params.id, function(err, object) {
var result = validateRequest(req, false, db, function(err) {
if (err) {
throw err;
res.send(err, 400);
} else {
res.send(object);
that.update(req, db, req.params.id, function(err, object) {
if (err) {
throw err;
} else {
res.send(object);
}
});
}
});
});
Expand Down
38 changes: 29 additions & 9 deletions lib/screens.js
Expand Up @@ -25,21 +25,25 @@ function getDefaultScreen(req) {
* Requires:
* req - web request,
* beingCreated - true if this screen is being created for the first time and
* false otherwise
* Returns: true if the request is valid to create/update a screen
* or an error message otherwise
* false otherwise,
* db - db connection
* Calls: callback([error]):
* error - if there was a validation issue, this is an error message that
* explains it; otherwise, this argument is not provided.
*/
function validateScreen(req, beingCreated) {
function validateScreen(req, beingCreated, db, callback) {
var body = req.body;
var title = body.title;
var isStart = body.isStart;
var secure = body.secure;

// TODO: validate isStart and layout
if (!title) {
return 'Screen must have a title.';
callback('Screen must have a title.');
return;
} else if (title.length < 1 || title.length > 20) {
return 'Screen must have a title between 1 than 20 characters long.';
callback('Screen must have a title between 1 than 20 characters long.');
return;
}

if (isStart !== undefined) {
Expand All @@ -50,7 +54,8 @@ function validateScreen(req, beingCreated) {
}

if (typeof isStart !== 'boolean') {
return 'Screen must have an isStart boolean.';
callback('Screen must have an isStart boolean.');
return;
}
}

Expand All @@ -62,11 +67,26 @@ function validateScreen(req, beingCreated) {
}

if (typeof secure !== 'boolean') {
return 'Screen must have a secure boolean.';
callback('Screen must have a secure boolean.');
return;
}
}

return true;
exports.list(req, db, function(err, screenList) {
if (err) {
throw err;
} else {
for (var i = 0; i < screenList.length; i++) {
if (screenList[i].title.toLowerCase() === title.toLowerCase()) {
callback('Screen must have a unique case-insensitive title.');
return;
}
}

// everything has been validated; there are no errors
callback();
}
});
}

exports = module.exports = scaffold.generate(['projects'], ['components'],
Expand Down

0 comments on commit 613a738

Please sign in to comment.