0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00
ghost/core/server/models/plugins/order.js
Naz 7326241718 🐛 Fixed server error for repeated order query parameter
closes #12263

- Express parses repeated query parameters as an array (req.query properties). Because there is no clear reason on why not to support this behavior extended order parameter parsing logic to handle arrays. This follows the rule of "liberal inputs, conservative outputs"
- Example supported query string for ordering can now look like: `?order=featured&order=published_at asc`, the priority of the order stays the same with the most significant appearing first and least significant last
2020-11-03 00:15:24 +13:00

62 lines
2.1 KiB
JavaScript

const _ = require('lodash');
const order = function order(Bookshelf) {
Bookshelf.Model = Bookshelf.Model.extend({
orderAttributes() {},
parseOrderOption: function (orderQueryString, withRelated) {
let orderAttributes;
let result;
let rules = [];
orderAttributes = this.orderAttributes();
if (withRelated && withRelated.indexOf('count.posts') > -1) {
orderAttributes.push('count.posts');
}
result = {};
// CASE: repeat order query parameter keys are present
if (_.isArray(orderQueryString)) {
orderQueryString.forEach((qs) => {
rules.push(...qs.split(','));
});
} else {
rules = orderQueryString.split(',');
}
_.each(rules, function (rule) {
let match;
let field;
let direction;
match = /^([a-z0-9_.]+)\s+(asc|desc)$/i.exec(rule.trim());
// invalid order syntax
if (!match) {
return;
}
field = match[1].toLowerCase();
direction = match[2].toUpperCase();
const matchingOrderAttribute = orderAttributes.find((orderAttribute) => {
// NOTE: this logic assumes we use different field names for "parent" and "child" relations.
// E.g.: ['parent.title', 'child.title'] and ['child.title', 'parent.title'] - would not
// distinguish on which relation to sort neither which order to pick the fields on.
// For more context see: https://github.com/TryGhost/Ghost/pull/12226#discussion_r493085098
return orderAttribute.endsWith(field);
});
if (!matchingOrderAttribute) {
return;
}
result[matchingOrderAttribute] = direction;
});
return result;
}
});
};
module.exports = order;