fix: #9580, proper 404 when ajaxifying

v1.18.x
Barış Soner Uşaklı 4 years ago
parent 09f5179216
commit 9ebfdeb7ee

@ -7,6 +7,7 @@ const validator = require('validator');
const meta = require('../meta');
const plugins = require('../plugins');
const middleware = require('../middleware');
const helpers = require('../middleware/helpers');
exports.handle404 = function handle404(req, res) {
const relativePath = nconf.get('relative_path');
@ -22,7 +23,13 @@ exports.handle404 = function handle404(req, res) {
if (isClientScript.test(req.url)) {
res.type('text/javascript').status(404).send('Not Found');
} else if (req.path.startsWith(`${relativePath}/assets/uploads`) || (req.get('accept') && !req.get('accept').includes('text/html')) || req.path === '/favicon.ico') {
} else if (
!res.locals.isAPI && (
req.path.startsWith(`${relativePath}/assets/uploads`) ||
(req.get('accept') && !req.get('accept').includes('text/html')) ||
req.path === '/favicon.ico'
)
) {
meta.errors.log404(req.path || '');
res.sendStatus(404);
} else if (req.accepts('html')) {
@ -41,7 +48,11 @@ exports.send404 = async function (req, res) {
res.status(404);
const path = String(req.path || '');
if (res.locals.isAPI) {
return res.json({ path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]' });
return res.json({
path: validator.escape(path.replace(/^\/api/, '')),
title: '[[global:404.title]]',
bodyClass: helpers.buildBodyClass(req, res),
});
}
if (req.method === 'GET') {
@ -49,5 +60,9 @@ exports.send404 = async function (req, res) {
}
await middleware.buildHeaderAsync(req, res);
await res.render('404', { path: validator.escape(path), title: '[[global:404.title]]' });
await res.render('404', {
path: validator.escape(path),
title: '[[global:404.title]]',
bodyClass: helpers.buildBodyClass(req, res),
});
};

@ -1,5 +1,9 @@
'use strict';
const winston = require('winston');
const validator = require('validator');
const slugify = require('../slugify');
const helpers = module.exports;
helpers.try = function (middleware) {
@ -20,3 +24,34 @@ helpers.try = function (middleware) {
}
};
};
helpers.buildBodyClass = function (req, res, templateData = {}) {
const clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, '');
const parts = clean.split('/').slice(0, 3);
parts.forEach((p, index) => {
try {
p = slugify(decodeURIComponent(p));
} catch (err) {
winston.error(err.stack);
p = '';
}
p = validator.escape(String(p));
parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`;
});
if (templateData.template && templateData.template.topic) {
parts.push(`page-topic-category-${templateData.category.cid}`);
parts.push(`page-topic-category-${slugify(templateData.category.name)}`);
}
if (Array.isArray(templateData.breadcrumbs)) {
templateData.breadcrumbs.forEach((crumb) => {
if (crumb && crumb.hasOwnProperty('cid')) {
parts.push(`parent-category-${crumb.cid}`);
}
});
}
parts.push(`page-status-${res.statusCode}`);
return parts.join(' ');
};

@ -2,14 +2,14 @@
const nconf = require('nconf');
const validator = require('validator');
const winston = require('winston');
const plugins = require('../plugins');
const meta = require('../meta');
const translator = require('../translator');
const widgets = require('../widgets');
const utils = require('../utils');
const slugify = require('../slugify');
const helpers = require('./helpers');
const relative_path = nconf.get('relative_path');
@ -31,7 +31,7 @@ module.exports = function (middleware) {
options.relative_path = relative_path;
options.template = { name: template, [template]: true };
options.url = (req.baseUrl + req.path.replace(/^\/api/, ''));
options.bodyClass = buildBodyClass(req, res, options);
options.bodyClass = helpers.buildBodyClass(req, res, options);
const buildResult = await plugins.hooks.fire(`filter:${template}.build`, { req: req, res: res, templateData: options });
if (res.headersSent) {
@ -123,34 +123,4 @@ module.exports = function (middleware) {
const translated = await translator.translate(str, language);
return translator.unescape(translated);
}
function buildBodyClass(req, res, templateData) {
const clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, '');
const parts = clean.split('/').slice(0, 3);
parts.forEach((p, index) => {
try {
p = slugify(decodeURIComponent(p));
} catch (err) {
winston.error(err.stack);
p = '';
}
p = validator.escape(String(p));
parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`;
});
if (templateData.template.topic) {
parts.push(`page-topic-category-${templateData.category.cid}`);
parts.push(`page-topic-category-${slugify(templateData.category.name)}`);
}
if (templateData.breadcrumbs) {
templateData.breadcrumbs.forEach((crumb) => {
if (crumb.hasOwnProperty('cid')) {
parts.push(`parent-category-${crumb.cid}`);
}
});
}
parts.push(`page-status-${res.statusCode}`);
return parts.join(' ');
}
};

Loading…
Cancel
Save