Skip to content

Commit

Permalink
Merge pull request pencilblue#693 from pencilblue/0.4.1
Browse files Browse the repository at this point in the history
0.4.1
  • Loading branch information
brianhyder committed Jul 19, 2015
2 parents 1c655bf + bfab3f3 commit 2217dc8
Show file tree
Hide file tree
Showing 88 changed files with 4,292 additions and 2,729 deletions.
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"to-markdown": "~0.0.2",
"markdown": "~0.5.0",
"danialfarid-angular-file-upload": "~1.6.12",
"ng-sortable": "~1.1.6"
"ng-sortable": "~1.1.6",
"rangy-release": "~1.3.0"
}
}
10 changes: 3 additions & 7 deletions controllers/api/api_action_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
*/

//dependencies
var async = require('async');
var util = require('../../include/util.js');
var async = require('async');
var util = require('../../include/util.js');

module.exports = function ApiActionControllerModule(pb) {

//module dependencies
//pb dependencies
var BaseController = pb.BaseController;
var PluginService = pb.PluginService;
var RequestHandler = pb.RequestHandler;

/**
* Controller interface used to map simple actions to handlers and provide
Expand All @@ -35,8 +33,6 @@ module.exports = function ApiActionControllerModule(pb) {
* @extends BaseController
*/
function ApiActionController(){}

//inheritance
util.inherits(ApiActionController, BaseController);

/**
Expand Down
143 changes: 113 additions & 30 deletions controllers/api/base_api_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ module.exports = function(pb) {
*/
function BaseApiController(){}
util.inherits(BaseApiController, pb.BaseController);

/**
* Indicates if a field should be part of the projection
* @static
* @readonly
* @property FIELD_ON
* @type {String}
*/
BaseApiController.FIELD_ON = '1';

/**
* Indicates if a field should be part of the projection
* @static
* @readonly
* @property FIELD_OFF
* @type {String}
*/
BaseApiController.FIELD_OFF = '0';

/**
* Retrieves a resource by ID where :id is a path parameter
Expand Down Expand Up @@ -82,54 +100,120 @@ module.exports = function(pb) {
}

//process select
var select = null;
var rawSelect = q.$select;
if (pb.ValidationService.isNonEmptyStr(rawSelect, true)) {
var select = {};
var pieces = rawSelect.split(',');
pieces.forEach(function(rawStatement) {
var selectResult = this.processSelect(q.$select);

//process the order
var orderResult = this.processOrder(q.$order);

//process where
var whereResult = this.processWhere(q);

//when failures occur combine them into a one big error and throw it to
//stop execution
var failures = selectResult.failures.concat(orderResult.failures).concat(whereResult.failures);
if (failures.length > 0) {
throw pb.BaseObjectService.validationError(failures);
}

return {
select: selectResult.select,
where: whereResult.where,
order: orderResult.order,
limit: limit,
offset: offset
};
};

/**
* Processes the query string to develop the where clause for the query request
* @method processWhere
* @param {Object} q The hash of all query parameters from the request
* @return {Object}
*/
BaseApiController.prototype.processWhere = function(q) {
var where = null;
var failures = [];

//TODO provide a default implementation
return {
where: where,
failures: failures
};
};

/**
* Processes the value of a $order query string variable
* @method processOrder
* @param {String} rawOrder
* @return {Object} Contains the order statement and an array of failures
*/
BaseApiController.prototype.processOrder = function(rawOrder) {console.log(rawOrder);
var order = null;
var failures = [];

if (pb.ValidationService.isNonEmptyStr(rawOrder, true)) {

order = [];
var orderPieces = rawOrder.split(',');
orderPieces.forEach(function(rawStatement) {

var statement = rawStatement.split('=');
if (statement.length == 2 && pb.ValidationService.isNonEmptyStr(statement[0], true) && (statement[1] === '1' || statement[1] === '0')) {
if (statement.length === 2 &&
pb.ValidationService.isNonEmptyStr(statement[0], true) &&
pb.ValidationService.isInt(statement[1], true)) {

select[statement[0]] = parseInt(statement[1]);
var ordering = {};
ordering[statement[0]] = parseInt(statement[1]) > 0 ? pb.DAO.ASC : pb.DAO.DESC;
order.push(ordering);
}
else {
var failures = [ pb.BaseObjectService.validationFailure('$select', 'An invalid select statement was provided: ' + statement[0] + '=' + statement[1]) ];
return cb(pb.BaseObjectService.validationError(failures));

var msg = util.format('An invalid order statement was provided: %s=%s', statement[0], statement[1]);
failures.push(pb.BaseObjectService.validationFailure('$order', msg));
}
});
}
}

return {
order: order,
failures: failures
};
};

/**
* Processes the value of a $select query string variable
* @method processSelect
* @param {String} rawSelect
* @return {Object} Contains the select statement and an array of failures
*/
BaseApiController.prototype.processSelect = function(rawSelect) {
var select = null;
var failures = [];

//process the order
var order = null;
var rawOrder = q.$order;
if (pb.ValidationService.isNonEmptyStr(rawSelect, true)) {
var order = [];
var pieces = rawSelect.split(',');
pieces.forEach(function(rawStatement) {

select = {};
var selectPieces = rawSelect.split(',');
selectPieces.forEach(function(rawStatement) {

var statement = rawStatement.split('=');
if (statement.length == 2 && pb.ValidationService.isNonEmptyStr(statement[0], true) && pb.ValidationService.isInt(statement[1], true)) {
if (statement.length === 2 &&
pb.ValidationService.isNonEmptyStr(statement[0], true) &&
(statement[1] === BaseApiController.FIELD_ON || statement[1] === BaseApiController.FIELD_OFF)) {

order.push([statement[0], parseInt(statement[1]) > 0 ? pb.DAO.ASC : pb.DAO.DESC ]);
select[statement[0]] = parseInt(statement[1]);
}
else {
var failures = [ pb.BaseObjectService.validationFailure('$order', 'An invalid order statement was provided: ' + statement[0] + '=' + statement[1]) ];
return cb(pb.BaseObjectService.validationError(failures));

var msg = util.format('An invalid select statement was provided: %s=%s', statement[0], statement[1]);
failures.push(pb.BaseObjectService.validationFailure('$select', msg));
}
});
}

//process where
var where = {};
//TODO implement a where clause parser

return options = {
return {
select: select,
where: where,
limit: limit,
offset: offset
failures: failures
};
};

Expand Down Expand Up @@ -210,7 +294,6 @@ module.exports = function(pb) {
* @return {Function} That can prepare a response and execute the callback
*/
BaseApiController.prototype.handleSave = function(cb, isCreate) {
var self = this;
return function(err, obj) {
if (util.isError(err)) {
return cb(err);
Expand Down
43 changes: 17 additions & 26 deletions controllers/base_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
*/

//dependencies
var url = require('url');
var Sanitizer = require('sanitize-html');
var util = require('../include/util.js');
var url = require('url');
var util = require('../include/util.js');

module.exports = function BaseControllerModule(pb) {

Expand All @@ -29,7 +28,7 @@ module.exports = function BaseControllerModule(pb) {
* @class BaseController
* @constructor
*/
function BaseController(){};
function BaseController(){}

//constants
/**
Expand Down Expand Up @@ -68,17 +67,6 @@ module.exports = function BaseControllerModule(pb) {
* @type {String}
*/
var ALERT_PATTERN = '<div class="alert %s error_success">%s<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button></div>';

/**
* The prefix in the content-type header that indicates the charset used in
* the encoding
* @static
* @private
* @readonly
* @property CHARSET_HEADER_PREFIX
* @type {String}
*/
var CHARSET_HEADER_PREFIX = 'charset=';

/**
* A mapping that converts the HTTP standard for content-type encoding and
Expand Down Expand Up @@ -221,7 +209,8 @@ module.exports = function BaseControllerModule(pb) {
BaseController.prototype.formError = function(message, redirectLocation, cb) {

this.session.error = message;
cb(pb.RequestHandler.generateRedirect(pb.config.siteRoot + redirectLocation));
var uri = pb.UrlService.createSystemUrl(redirectLocation);
cb(pb.RequestHandler.generateRedirect(uri));
};

/**
Expand All @@ -231,14 +220,14 @@ module.exports = function BaseControllerModule(pb) {
* @param {Function} cb
*/
BaseController.prototype.displayErrorOrSuccessCallback = function(flag, cb) {
if(this.session['error']) {
var error = this.session['error'];
delete this.session['error'];
if(this.session.error) {
var error = this.session.error;
delete this.session.error;
cb(null, new pb.TemplateValue(util.format(ALERT_PATTERN, 'alert-danger', this.localizationService.get(error)), false));
}
else if(this.session['success']) {
var success = this.session['success'];
delete this.session['success'];
else if(this.session.success) {
var success = this.session.success;
delete this.session.success;
cb(null, new pb.TemplateValue(util.format(ALERT_PATTERN, 'alert-success', this.localizationService.get(success)), false));
}
else {
Expand Down Expand Up @@ -334,7 +323,9 @@ module.exports = function BaseControllerModule(pb) {
// 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
if (totalLength > 1e6) {
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
cb(new PBError("POST limit reached! Maximum of 1MB.", 400), null);
var err = new Error("POST limit reached! Maximum of 1MB.");
err.code = 400;
cb(err, null);
}
});
this.req.on('end', function () {
Expand All @@ -358,13 +349,13 @@ module.exports = function BaseControllerModule(pb) {
if (typeof queryObject[requiredParameters[i]] === 'undefined') {
return this.localizationService.get('FORM_INCOMPLETE');
}
else if (queryObject[requiredParameters[i]].length == 0) {
else if (queryObject[requiredParameters[i]].length === 0) {
return this.localizationService.get('FORM_INCOMPLETE');
}
}

if(queryObject['password'] && queryObject['confirm_password']) {
if(queryObject['password'] != queryObject['confirm_password']) {
if(queryObject.password && queryObject.confirm_password) {
if(queryObject.password !== queryObject.confirm_password) {
return this.localizationService.get('PASSWORD_MISMATCH');
}
}
Expand Down
Loading

0 comments on commit 2217dc8

Please sign in to comment.