Added maxPeriodic limit support to limit service

refs https://github.com/TryGhost/Team/issues/588

- The limit service can now be initialized with a config which has a 'maxPeriodic' key identifying it's a special type of limit taking subscription cycles into account
- Example configuration can be found in the included unit tests
This commit is contained in:
Naz 2021-05-06 15:49:16 +04:00
parent 1483a5c758
commit 0d242b96ef
2 changed files with 52 additions and 3 deletions

View File

@ -1,4 +1,4 @@
const {MaxLimit, FlagLimit, AllowlistLimit} = require('./limit');
const {MaxLimit, MaxPeriodicLimit, FlagLimit, AllowlistLimit} = require('./limit');
const config = require('./config');
const _ = require('lodash');
@ -12,11 +12,12 @@ class LimitService {
*
* @param {Object} options
* @param {Object} [options.limits] - hash containing limit configurations keyed by limit name and containing
* @param {Object} [options.subscription] - hash containing subscription configuration with interval and startDate properties
* @param {String} options.helpLink - URL pointing to help resources for when limit is reached
* @param {Object} options.db - knex db connection instance or other data source for the limit checks
* @param {Object} options.errors - instance of errors compatible with Ghost-Ignition's errors (https://github.com/TryGhost/Ignition#errors)
*/
loadLimits({limits = {}, helpLink, db, errors}) {
loadLimits({limits = {}, subscription, helpLink, db, errors}) {
if (!errors) {
throw new Error(`Config Missing: 'errors' is required.`);
}
@ -38,6 +39,13 @@ class LimitService {
this.limits[name] = new AllowlistLimit({name, config: limitConfig, helpLink, errors});
} else if (_.has(limitConfig, 'max')) {
this.limits[name] = new MaxLimit({name: name, config: limitConfig, helpLink, db, errors});
} else if (_.has(limitConfig, 'maxPeriodic')) {
if (subscription === undefined) {
throw new errors.IncorrectUsageError({message: 'Attempted to setup a periodic max limit without a subscription'});
}
const maxPeriodicLimitConfig = Object.assign({}, limitConfig, subscription);
this.limits[name] = new MaxPeriodicLimit({name: name, config: maxPeriodicLimitConfig, helpLink, db, errors});
} else {
this.limits[name] = new FlagLimit({name: name, config: limitConfig, helpLink, errors});
}
@ -101,6 +109,7 @@ module.exports = LimitService;
/**
* @typedef {Object} LimitConfig
* @prop {Number} [max] - max limit
* @prop {Number} [maxPeriodic] - max limit for a period
* @prop {Boolean} [disabled] - flag disabling/enabling limit
* @prop {String} error - custom error to be displayed when the limit is reached
* @prop {Function} [currentCountQuery] - function returning count for the "max" type of limit

View File

@ -3,7 +3,7 @@
require('./utils');
const LimitService = require('../lib/limit-service');
const {MaxLimit, FlagLimit} = require('../lib/limit');
const {MaxLimit, MaxPeriodicLimit, FlagLimit} = require('../lib/limit');
const errors = require('./fixtures/errors');
@ -83,6 +83,46 @@ describe('Limit Service', function () {
limitService.isLimited('members').should.be.false();
});
it('can load a periodic max limit', function () {
const limitService = new LimitService();
let limits = {
emails: {
maxPeriodic: 3
}
};
let subscription = {
interval: 'month',
startDate: '2021-09-18T19:00:52Z'
};
limitService.loadLimits({limits, subscription, errors});
limitService.limits.should.be.an.Object().with.properties(['emails']);
limitService.limits.emails.should.be.an.instanceOf(MaxPeriodicLimit);
limitService.isLimited('emails').should.be.true();
limitService.isLimited('staff').should.be.false();
});
it('throws when loadding a periodic max limit without a subscription', function () {
const limitService = new LimitService();
let limits = {
emails: {
maxPeriodic: 3
}
};
try {
limitService.loadLimits({limits, errors});
throw new Error('Should have failed earlier...');
} catch (error) {
error.errorType.should.equal('IncorrectUsageError');
error.message.should.match(/periodic max limit without a subscription/);
}
});
it('can load multiple limits', function () {
const limitService = new LimitService();