we-core
Version:
We.js is a node.js framework for build real time applications, sites or blogs!
438 lines (368 loc) • 10.7 kB
JavaScript
const haveAndAcceptsHtmlResponse = require('../../Router/haveAndAcceptsHtmlResponse.js');
module.exports = {
/**
* res.ok default success response
*
* By defalt they will get the record from res.locals.data
*
* @param {Object} data opctional data
*/
ok(data) {
const res = this.res,
req = this.req,
we = req.we;
res.status(200);
if (!data) {
data = res.locals.data || {};
} else {
if (!res.locals.data) res.locals.data = data;
}
// use this hook in one we.js plugin to change a res.ok response
we.hooks.trigger('we:before:send:okResponse', {
req: req,
res: res,
data: data
}, (err)=> {
if (err) we.log.error(err);
// if accepts html and have the html response format:
if (haveAndAcceptsHtmlResponse(req, res)) {
if (req.method == 'POST' && res.locals.action == 'edit' && res.locals.redirectTo) {
return res.redirect(res.locals.redirectTo);
}
}
res.format(we.responses.formaters);
});
},
/**
* Record created response
*
* By defalt they will get the record from res.locals.data
*
* @param {Object} data record data
*/
created(data) {
const res = this.res,
req = this.req,
we = req.we;
res.status(201);
if (!data) {
data = res.locals.data || {};
} else {
if (!res.locals.data) res.locals.data = data;
}
// use this hook in one we.js plugin to change a res.ok response
we.hooks.trigger('we:before:send:createdResponse', {
req: req,
res: res,
data: data
}, (err)=> {
if (err) we.log.error(err);
if (haveAndAcceptsHtmlResponse(req, res)) {
// redirect if are one html response
if (res.locals.skipRedirect) {
return res.view(data);
} else if (res.locals.redirectTo) {
return res.redirect(res.locals.redirectTo);
} else {
// push id to paramsArray for use in urlTo
req.paramsArray.push(res.locals.data.id);
// redirect to content after create
return res.redirect(we.router.urlTo(res.locals.model + '.findOne', req.paramsArray));
}
}
res.format(we.responses.formaters);
});
},
/**
* Record updated response
*
* By defalt they will get the record from res.locals.data
*
* @param {Object} data optional data
*/
updated(data) {
const res = this.res,
req = this.req,
we = req.we;
res.status(200);
if (!data) {
data = res.locals.data || {};
} else {
if (!res.locals.data) res.locals.data = data;
}
// use this hook in one we.js plugin to change a res.ok response
we.hooks.trigger('we:before:send:updatedResponse', {
req: req,
res: res,
data: data
}, (err)=> {
if (err) we.log.error(err);
if (haveAndAcceptsHtmlResponse(req, res)) {
// if is edit record use the redirectTo feature
if (res.locals.redirectTo) {
return res.redirect(res.locals.redirectTo);
} else {
// push id to paramsArray for use in urlTo
req.paramsArray.push(res.locals.data.id);
// redirect to content after create
return res.redirect(we.router.urlTo(res.locals.model + '.findOne', req.paramsArray));
}
}
res.format(we.responses.formaters);
});
},
/**
* Deleted response
*
* redirect for html responses
*/
deleted() {
const res = this.res,
req = this.req,
we = req.we;
res.status(204);
// use this hook in one we.js plugin to change a res.ok response
we.hooks.trigger('we:before:send:deletedResponse', {
req: req,
res: res
}, ()=> {
if (haveAndAcceptsHtmlResponse(req, res)) {
if (
res.locals.redirectTo &&
(we.router.urlTo(res.locals.model + '.findOne', req.paramsArray) != res.locals.redirectTo)
) {
return res.redirect(res.locals.redirectTo);
} else {
res.locals.deleteRedirectUrl = we.router.urlTo(res.locals.model + '.find', req.paramsArray);
return res.redirect((res.locals.deleteRedirectUrl || '/'));
}
}
res.format(req.we.responses.formaters);
});
},
/**
* View response usefull if we have the we-plugin-view installed to send html pages in response
*
* @param {Object} data Data to send that overrides data from res.locals.data
*/
view(data) {
const req = this.req,
res = this.res;
if (!data) {
data = res.locals.data || {};
} else {
if (!res.locals.data) res.locals.data = data;
}
if (req.haveAlias) {
// is a target how have alias then redirect to it
res.writeHead(307, {
'Location': req.haveAlias.alias,
'Content-Type': 'text/plain',
'Cache-Control':'public, max-age=345600',
'Expires': new Date(Date.now() + 345600000).toUTCString()
});
return res.send();
}
if (req.method && req.method == 'HEAD') {
// HEAD requests dont have body data then ignore format.
return res.send();
}
res.format(req.we.responses.formaters);
},
/**
* Forbidden response
*
* @param {String} data Optional extra message
*/
forbidden(data) {
const res = this.res,
req = this.req;
let __ = ( res.locals.__ || req.we.i18n.__ );
if (typeof data == 'string') {
res.addMessage('error', {
text: data
});
data = null;
}
res.status(403);
res.locals.title = __('response.forbidden.title');
if (haveAndAcceptsHtmlResponse(req, res)) {
res.locals.layoutName = 'fullwidth';
res.locals.template = '403';
}
// delete the data that user dont have access:
delete res.locals.data;
// add one message with forbidden to send in response:
res.addMessage('warn', { text: 'forbidden' });
res.format(req.we.responses.formaters);
},
/**
* Not found response
*
* @param {String} data optional 404 error message
*/
notFound(data) {
const res = this.res,
req = this.req,
we = req.we;
if (typeof data == 'string') {
res.addMessage('error', {
text: data
});
data = null;
}
res.locals.data = null;
if (we.config.enable404Log) {
if (we.env == 'dev') {
console.trace('404', {
method: req.method,
path: req.path
});
} else {
we.log.info('Not found 404 ', {
url: req.url,
method: req.method,
query: req.query,
controller: res.locals.controller,
action: res.locals.action
});
}
}
res.locals.title = req.__('response.notFound.title');
res.status(404);
if (haveAndAcceptsHtmlResponse(req, res)) {
res.locals.layoutName = 'fullwidth';
res.locals.template = '404';
}
delete res.locals.data;
res.format(we.responses.formaters);
},
/**
* Server error response
*
* @param {Object} data the error
*/
serverError(data) {
const res = this.res,
req = this.req;
let __ = ( req.__ || res.locals.__ || req.we.i18n.__ );
res.status(500);
req.we.log.error('ServerError:', data);
res.locals.title = __('response.serveError.title');
if (data && typeof data == 'string') {
res.addMessage('error', String(data));
}
if (haveAndAcceptsHtmlResponse(req, res)) {
res.locals.template = '500';
res.locals.layoutName = 'fullwidth';
}
delete res.locals.data;
// send the response
res.format(req.we.responses.formaters);
},
/**
* bad request response
*
* @param {Obejct|String} data message
*/
badRequest(data) {
const res = this.res,
req = this.req;
res.status(400);
if (req.we.env == 'dev') {
console.trace('400', req.path);
}
if (data && typeof data == 'string') {
res.addMessage('warning', String(data));
}
if (haveAndAcceptsHtmlResponse(req, res)) {
// if is html
if (!res.locals.template) res.locals.template = '400';
}
delete res.locals.data;
// send the response
res.format(req.we.responses.formaters);
},
/**
* Sequelize query error parser
*
* @param {Object} err The database error
*/
queryError(err) {
const res = this.res,
req = this.req,
log = req.we.log;
let __ = ( req.__ || res.locals.__ || req.we.i18n.__ );
if (err) {
// parse all sequelize validation erros for html (we-plugin-view)
if (
haveAndAcceptsHtmlResponse(req, res) &&
err.name === 'SequelizeValidationError'
) {
// query validation error ...
res.locals.validationError = {};
err.errors.forEach( (err)=> {
if (!res.locals.validationError[err.path])
res.locals.validationError[err.path] = [];
res.locals.validationError[err.path].push({
field: err.path,
rule: err.type,
message: __(err.message)
});
});
} else if (err.name === 'SequelizeDatabaseError') {
// parse sequelize database errors
if (err.message) {
res.addMessage('error', err.message);
}
} else if (typeof err == 'string') {
res.addMessage('error', err);
} else if (err.name != 'SequelizeValidationError') {
log.error('responses.queryError:unknowError ', {
path: req.path,
error: {
message: err.message,
name: err.name,
stack: err.stack
}
});
}
// default error handler, push erros to messages and let response formaters resolve how to format this messages
if (err.errors) {
err.errors.forEach( (e)=> {
res.addMessage('error', e.message, {
field: e.path,
rule: e.type,
errorName: err.name,
value: e.value,
level: 'error',
code: ( e.code || err.code ) // code if avaible
});
});
}
}
if (err && err.name == 'SequelizeValidationError') {
res.status(400);
} else {
res.status(500);
delete res.locals.data;
}
res.format(req.we.responses.formaters);
},
/**
* We.js core redirect
*
* @param {String} s response status
* @param {String} p path
*/
goTo(s ,p) {
// save locals messages to flash
this.res.moveLocalsMessagesToFlash();
// use default redirect
if (p) {
this.res.redirect(s, p);
} else {
this.res.redirect(s);
}
}
};