mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
🐛 Fixed Tiers API erroring when invalid filter passed (#19845)
closes ENG-730 closes https://linear.app/tryghost/issue/ENG-730/ We've updated the input serializer to parse the filter, and responded with an error if it cannot be parsed correctly. Now that it's parsed, we can pass a mongo query object through the stack, which will lend itself to better typing for this code, which is a direction we want to go in anyway. We've had to update all the internal usages of the `browse` method to use mongo query objects.
This commit is contained in:
parent
36f11a65a0
commit
5a5ddcb609
@ -1,10 +1,26 @@
|
||||
const {BadRequestError} = require('@tryghost/errors');
|
||||
const localUtils = require('../../index');
|
||||
const nql = require('@tryghost/nql-lang');
|
||||
const tpl = require('@tryghost/tpl');
|
||||
|
||||
const messages = {
|
||||
invalidNQLFilter: 'The NQL filter you passed was invalid.'
|
||||
};
|
||||
|
||||
const forceActiveFilter = (frame) => {
|
||||
if (frame.options.filter) {
|
||||
frame.options.filter = `(${frame.options.filter})+active:true`;
|
||||
frame.options.filter = {
|
||||
$and: [
|
||||
{
|
||||
active: true
|
||||
},
|
||||
frame.options.filter
|
||||
]
|
||||
};
|
||||
} else {
|
||||
frame.options.filter = 'active:true';
|
||||
frame.options.filter = {
|
||||
active: true
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -41,6 +57,18 @@ function convertTierInput(input) {
|
||||
|
||||
module.exports = {
|
||||
all(_apiConfig, frame) {
|
||||
if (frame.options.filter) {
|
||||
try {
|
||||
frame.options.filter = nql.parse(frame.options.filter);
|
||||
} catch (err) {
|
||||
throw new BadRequestError({
|
||||
message: tpl(messages.invalidNQLFilter)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
frame.options.filter = null;
|
||||
}
|
||||
|
||||
if (localUtils.isContentAPI(frame)) {
|
||||
// CASE: content api can only have active tiers
|
||||
forceActiveFilter(frame);
|
||||
|
@ -55,7 +55,9 @@ const initMembersCSVImporter = ({stripeAPIService}) => {
|
||||
},
|
||||
getTierByName: async (name) => {
|
||||
const tiers = await tiersService.api.browse({
|
||||
filter: `name:'${name}'`
|
||||
filter: {
|
||||
name
|
||||
}
|
||||
});
|
||||
|
||||
if (tiers.data.length > 0) {
|
||||
|
@ -86,7 +86,8 @@ module.exports = class TierRepository {
|
||||
* @returns {Promise<import('@tryghost/tiers/lib/Tier')[]>}
|
||||
*/
|
||||
async getAll(options = {}) {
|
||||
const filter = nql(options.filter, {});
|
||||
const filter = nql();
|
||||
filter.filter = options.filter || {};
|
||||
return Promise.all(this.#store.slice().filter((item) => {
|
||||
return filter.queryJSON(this.toPrimitive(item));
|
||||
}).map((tier) => {
|
||||
|
@ -55,7 +55,8 @@ class InMemoryTierRepository {
|
||||
* @returns {Promise<Tier[]>}
|
||||
*/
|
||||
async getAll(options = {}) {
|
||||
const filter = nql(options.filter, {});
|
||||
const filter = nql();
|
||||
filter.filter = options.filter || {};
|
||||
return this.#store.slice().filter((item) => {
|
||||
return filter.queryJSON(this.toPrimitive(item));
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
const ObjectID = require('bson-objectid').default;
|
||||
const {BadRequestError} = require('@tryghost/errors');
|
||||
const {BadRequestError, IncorrectUsageError} = require('@tryghost/errors');
|
||||
const Tier = require('./Tier');
|
||||
|
||||
/**
|
||||
@ -42,11 +42,16 @@ module.exports = class TiersAPI {
|
||||
|
||||
/**
|
||||
* @param {object} [options]
|
||||
* @param {string} [options.filter] - An NQL filter string
|
||||
* @param {any} [options.filter] - A mongo query object
|
||||
*
|
||||
* @returns {Promise<Page<Tier>>}
|
||||
*/
|
||||
async browse(options = {}) {
|
||||
if (typeof options.filter === 'string') {
|
||||
throw new IncorrectUsageError({
|
||||
message: 'filter must be a mongo query object'
|
||||
});
|
||||
}
|
||||
const tiers = await this.#repository.getAll(options);
|
||||
|
||||
return {
|
||||
@ -83,7 +88,12 @@ module.exports = class TiersAPI {
|
||||
*/
|
||||
async readDefaultTier(options = {}) {
|
||||
const [defaultTier] = await this.#repository.getAll({
|
||||
filter: 'type:paid+active:true',
|
||||
filter: {
|
||||
$and: [
|
||||
{type: 'paid'},
|
||||
{active: true}
|
||||
]
|
||||
},
|
||||
limit: 1,
|
||||
...options
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user