mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 07:03:38 +00:00
feat: handle history version pagination params (#19594)
* feat: handle history version pagination params * fix: ts build error * chore: validate pagination params * chore: pr feedback and test
This commit is contained in:
parent
741baba5b5
commit
6408670a35
@ -22,6 +22,7 @@ jest.mock('../../../utils', () => ({
|
||||
cannot: {
|
||||
read: jest.fn(() => false),
|
||||
},
|
||||
sanitizeQuery: jest.fn((query) => query),
|
||||
})),
|
||||
};
|
||||
}
|
||||
@ -29,6 +30,10 @@ jest.mock('../../../utils', () => ({
|
||||
}));
|
||||
|
||||
describe('History version controller', () => {
|
||||
beforeEach(() => {
|
||||
mockFindVersionsPage.mockClear();
|
||||
});
|
||||
|
||||
describe('findMany', () => {
|
||||
it('should require contentType and documentId for collection types', () => {
|
||||
const ctx = {
|
||||
@ -135,4 +140,60 @@ describe('History version controller', () => {
|
||||
expect(response.data.length).toBe(1);
|
||||
expect(response.meta.pagination).toBeDefined();
|
||||
});
|
||||
|
||||
it('applies pagination params', async () => {
|
||||
const ctx = {
|
||||
state: {
|
||||
userAbility: {},
|
||||
},
|
||||
query: {
|
||||
contentType: 'api::test.test',
|
||||
},
|
||||
};
|
||||
|
||||
const historyVersionController = createHistoryVersionController({
|
||||
// @ts-expect-error - we're not mocking the entire strapi object
|
||||
strapi: { getModel: jest.fn(() => ({ kind: 'singleType' })) },
|
||||
});
|
||||
|
||||
/**
|
||||
* Applies default pagination params
|
||||
*/
|
||||
mockFindVersionsPage.mockResolvedValueOnce({
|
||||
results: [],
|
||||
pagination: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
});
|
||||
// @ts-expect-error partial context
|
||||
const mockResponse = await historyVersionController.findMany(ctx);
|
||||
expect(mockFindVersionsPage).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
);
|
||||
expect(mockResponse.meta.pagination.page).toBe(1);
|
||||
expect(mockResponse.meta.pagination.pageSize).toBe(10);
|
||||
|
||||
/**
|
||||
* Prevents invalid pagination params
|
||||
*/
|
||||
mockFindVersionsPage.mockResolvedValueOnce({
|
||||
results: [],
|
||||
pagination: {},
|
||||
});
|
||||
// @ts-expect-error partial context
|
||||
await historyVersionController.findMany({
|
||||
...ctx,
|
||||
query: { ...ctx.query, page: '-1', pageSize: '1000' },
|
||||
});
|
||||
expect(mockFindVersionsPage).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,6 +4,33 @@ import { getService as getContentManagerService } from '../../utils';
|
||||
import { getService } from '../utils';
|
||||
import { HistoryVersions } from '../../../../shared/contracts';
|
||||
|
||||
/**
|
||||
* Parses pagination params and makes sure they're within valid ranges
|
||||
*/
|
||||
const getValidPagination = ({ page, pageSize }: { page: any; pageSize: any }) => {
|
||||
let pageNumber = 1;
|
||||
let pageSizeNumber = 10;
|
||||
|
||||
if (page) {
|
||||
const parsedPage = parseInt(page, 10);
|
||||
pageNumber = parseInt(page, 10);
|
||||
|
||||
if (!Number.isNaN(parsedPage) && parsedPage >= 1) {
|
||||
pageNumber = parsedPage;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageSize) {
|
||||
const parsedPageSize = parseInt(pageSize, 10);
|
||||
|
||||
if (!Number.isNaN(parsedPageSize) && parsedPageSize >= 1 && parsedPageSize <= 100) {
|
||||
pageSizeNumber = parsedPageSize;
|
||||
}
|
||||
}
|
||||
|
||||
return { page: pageNumber, pageSize: pageSizeNumber };
|
||||
};
|
||||
|
||||
const createHistoryVersionController = ({ strapi }: { strapi: Strapi }) => {
|
||||
return {
|
||||
async findMany(ctx) {
|
||||
@ -18,22 +45,26 @@ const createHistoryVersionController = ({ strapi }: { strapi: Strapi }) => {
|
||||
throw new errors.ForbiddenError('contentType and documentId are required');
|
||||
}
|
||||
|
||||
const params = ctx.query as HistoryVersions.GetHistoryVersions.Request['query'];
|
||||
|
||||
/**
|
||||
* There are no permissions specifically for history versions,
|
||||
* but we need to check that the user can read the content type
|
||||
*/
|
||||
const permissionChecker = getContentManagerService('permission-checker').create({
|
||||
userAbility: ctx.state.userAbility,
|
||||
model: params.contentType,
|
||||
model: ctx.query.contentType,
|
||||
});
|
||||
|
||||
if (permissionChecker.cannot.read()) {
|
||||
return ctx.forbidden();
|
||||
}
|
||||
|
||||
const { results, pagination } = await getService(strapi, 'history').findVersionsPage(params);
|
||||
const params: HistoryVersions.GetHistoryVersions.Request['query'] =
|
||||
await permissionChecker.sanitizeQuery(ctx.query);
|
||||
|
||||
const { results, pagination } = await getService(strapi, 'history').findVersionsPage({
|
||||
...params,
|
||||
...getValidPagination({ page: params.page, pageSize: params.pageSize }),
|
||||
});
|
||||
|
||||
return { data: results, meta: { pagination } };
|
||||
},
|
||||
|
||||
@ -151,8 +151,7 @@ const createHistoryService = ({ strapi }: { strapi: LoadedStrapi }) => {
|
||||
async findVersionsPage(params: HistoryVersions.GetHistoryVersions.Request['query']) {
|
||||
const [{ results, pagination }, localeDictionary] = await Promise.all([
|
||||
query.findPage({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
...params,
|
||||
where: {
|
||||
$and: [
|
||||
{ contentType: params.contentType },
|
||||
|
||||
@ -33,7 +33,8 @@ export interface HistoryVersionDataResponse extends Omit<CreateHistoryVersion, '
|
||||
locale: Locale | null;
|
||||
}
|
||||
|
||||
interface Pagination {
|
||||
// Export to prevent the TS "cannot be named" error in the history service
|
||||
export interface Pagination {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
pageCount: number;
|
||||
@ -52,7 +53,7 @@ export declare namespace GetHistoryVersions {
|
||||
contentType: UID.ContentType;
|
||||
documentId?: Entity.ID;
|
||||
locale?: string;
|
||||
};
|
||||
} & Partial<Pick<Pagination, 'page' | 'pageSize'>>;
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user