chore(content-releases): enforce license limits for pending releases (#19208)

This commit is contained in:
markkaylor 2024-01-15 17:23:48 +01:00 committed by GitHub
parent 6cfcadfee1
commit 2b10ca9b97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 114 additions and 0 deletions

View File

@ -1,3 +1,4 @@
import EE from '@strapi/strapi/dist/utils/ee';
import type { CreateReleaseAction } from '../../../../shared/contracts/release-actions';
import createReleaseValidationService from '../validation';
@ -10,6 +11,12 @@ const baseStrapiMock = {
contentType: jest.fn(),
};
jest.mock('@strapi/strapi/dist/utils/ee', () => ({
features: {
get: jest.fn(),
},
}));
describe('Release Validation service', () => {
describe('validateEntryContentType', () => {
it('throws an error if the content type does not exist', () => {
@ -107,4 +114,88 @@ describe('Release Validation service', () => {
);
});
});
describe('validatePendingReleasesLimit', () => {
it('should throw an error if the default pending release limit has been reached', () => {
// @ts-expect-error - get is a mock
EE.features.get.mockReturnValue({});
const strapiMock = {
...baseStrapiMock,
db: {
query: jest.fn().mockReturnValue({
findWithCount: jest.fn().mockReturnValue([[], 4]),
}),
},
};
// @ts-expect-error Ignore missing properties
const releaseValidationService = createReleaseValidationService({ strapi: strapiMock });
expect(() => releaseValidationService.validatePendingReleasesLimit()).rejects.toThrow(
'You have reached the maximum number of pending releases'
);
});
it('should pass if the default pending release limit has NOT been reached', async () => {
// @ts-expect-error - get is a mock
EE.features.get.mockReturnValue({});
const strapiMock = {
...baseStrapiMock,
db: {
query: jest.fn().mockReturnValue({
findWithCount: jest.fn().mockReturnValue([[], 2]),
}),
},
};
// @ts-expect-error Ignore missing properties
const releaseValidationService = createReleaseValidationService({ strapi: strapiMock });
await expect(releaseValidationService.validatePendingReleasesLimit()).resolves.not.toThrow();
});
it('should throw an error if the license pending release limit has been reached', () => {
// @ts-expect-error - get is a mock
EE.features.get.mockReturnValue({
options: {
maximumReleases: 5,
},
});
const strapiMock = {
...baseStrapiMock,
db: {
query: jest.fn().mockReturnValue({
findWithCount: jest.fn().mockReturnValue([[], 5]),
}),
},
};
// @ts-expect-error Ignore missing properties
const releaseValidationService = createReleaseValidationService({ strapi: strapiMock });
expect(() => releaseValidationService.validatePendingReleasesLimit()).rejects.toThrow(
'You have reached the maximum number of pending releases'
);
});
it('should pass if the license pending release limit has NOT been reached', async () => {
// @ts-expect-error - get is a mock
EE.features.get.mockReturnValue({
options: {
maximumReleases: 5,
},
});
const strapiMock = {
...baseStrapiMock,
db: {
query: jest.fn().mockReturnValue({
findWithCount: jest.fn().mockReturnValue([[], 4]),
}),
},
};
// @ts-expect-error Ignore missing properties
const releaseValidationService = createReleaseValidationService({ strapi: strapiMock });
await expect(releaseValidationService.validatePendingReleasesLimit()).resolves.not.toThrow();
});
});
});

View File

@ -3,6 +3,7 @@ import { setCreatorFields, errors } from '@strapi/utils';
import type { LoadedStrapi, EntityService, UID } from '@strapi/types';
import _ from 'lodash/fp';
import { RELEASE_ACTION_MODEL_UID, RELEASE_MODEL_UID } from '../constants';
import type {
GetReleases,
@ -51,6 +52,8 @@ const createReleaseService = ({ strapi }: { strapi: LoadedStrapi }) => ({
async create(releaseData: CreateRelease.Request['body'], { user }: { user: UserInfo }) {
const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);
await getService('release-validation', { strapi }).validatePendingReleasesLimit();
return strapi.entityService.create(RELEASE_MODEL_UID, {
data: releaseWithCreatorFields,
});

View File

@ -1,5 +1,6 @@
import { errors } from '@strapi/utils';
import { LoadedStrapi } from '@strapi/types';
import EE from '@strapi/strapi/dist/utils/ee';
import type { Release } from '../../../shared/contracts/releases';
import type { CreateReleaseAction } from '../../../shared/contracts/release-actions';
import { RELEASE_MODEL_UID } from '../constants';
@ -49,6 +50,25 @@ const createReleaseValidationService = ({ strapi }: { strapi: LoadedStrapi }) =>
);
}
},
async validatePendingReleasesLimit() {
// Use the maximum releases option if it exists, otherwise default to 3
const maximumPendingReleases =
// @ts-expect-error - options is not typed into features
EE.features.get('cms-content-releases')?.options?.maximumReleases || 3;
const [, pendingReleasesCount] = await strapi.db.query(RELEASE_MODEL_UID).findWithCount({
filters: {
releasedAt: {
$null: true,
},
},
});
// Unlimited is a number that will never be reached like 9999
if (pendingReleasesCount >= maximumPendingReleases) {
throw new errors.ValidationError('You have reached the maximum number of pending releases');
}
},
});
export default createReleaseValidationService;