From 42252454c932b1c6dce4e88a52a0c24b9d4f045e Mon Sep 17 00:00:00 2001 From: muntaxir4 Date: Sun, 28 Jul 2024 05:07:19 +0530 Subject: [PATCH] API: Add pagination metadata to Project module --- apps/api/src/project/project.e2e.spec.ts | 38 +++++++-- .../src/project/service/project.service.ts | 79 +++++++++++++++---- 2 files changed, 97 insertions(+), 20 deletions(-) diff --git a/apps/api/src/project/project.e2e.spec.ts b/apps/api/src/project/project.e2e.spec.ts index 4bbb40c2..df558f6b 100644 --- a/apps/api/src/project/project.e2e.spec.ts +++ b/apps/api/src/project/project.e2e.spec.ts @@ -463,14 +463,29 @@ describe('Project Controller Tests', () => { it('should be able to fetch all projects of a workspace', async () => { const response = await app.inject({ method: 'GET', - url: `/project/all/${workspace1.id}?page=0`, + url: `/project/all/${workspace1.id}?page=0&limit=10`, headers: { 'x-e2e-user-email': user1.email } }) expect(response.statusCode).toBe(200) - expect(response.json().length).toEqual(2) + expect(response.json().items.length).toEqual(2) + + //check metadata + const metadata = response.json().metadata + expect(metadata.totalCount).toEqual(2) + expect(metadata.links.self).toBe( + `/project/all/${workspace1.id}?page=0&limit=10&sort=name&order=asc&search=` + ) + expect(metadata.links.first).toBe( + `/project/all/${workspace1.id}?page=0&limit=10&sort=name&order=asc&search=` + ) + expect(metadata.links.previous).toEqual(null) + expect(metadata.links.next).toEqual(null) + expect(metadata.links.last).toBe( + `/project/all/${workspace1.id}?page=0&limit=10&sort=name&order=asc&search=` + ) }) it('should not be able to fetch all projects of a non existing workspace', async () => { @@ -1722,9 +1737,22 @@ describe('Project Controller Tests', () => { 'x-e2e-user-email': user2.email } }) - expect(response.statusCode).toBe(200) - expect(response.json()).toHaveLength(1) + expect(response.json().items).toHaveLength(1) + + //check metadata + const metadata = response.json().metadata + expect(metadata.links.self).toBe( + `/project/${project3.id}/forks?page=0&limit=10` + ) + expect(metadata.links.first).toBe( + `/project/${project3.id}/forks?page=0&limit=10` + ) + expect(metadata.links.previous).toEqual(null) + expect(metadata.links.next).toEqual(null) + expect(metadata.links.last).toBe( + `/project/${project3.id}/forks?page=0&limit=10` + ) }) it('should not contain a forked project that has access level other than GLOBAL', async () => { @@ -1754,7 +1782,7 @@ describe('Project Controller Tests', () => { }) expect(response.statusCode).toBe(200) - expect(response.json()).toHaveLength(1) + expect(response.json().items).toHaveLength(1) }) }) }) diff --git a/apps/api/src/project/service/project.service.ts b/apps/api/src/project/service/project.service.ts index 18253372..88527fb8 100644 --- a/apps/api/src/project/service/project.service.ts +++ b/apps/api/src/project/service/project.service.ts @@ -29,6 +29,7 @@ import createEvent from '../../common/create-event' import { ProjectWithSecrets } from '../project.types' import { AuthorityCheckerService } from '../../common/authority-checker.service' import { ForkProject } from '../dto/fork.project/fork.project' +import { paginate } from '../../common/paginate' @Injectable() export class ProjectService { @@ -593,19 +594,30 @@ export class ProjectService { } }) - return forks - .slice(page * limit, (page + 1) * limit) - .filter(async (fork) => { - const allowed = - (await this.authorityCheckerService.checkAuthorityOverProject({ - userId: user.id, - entity: { id: fork.id }, - authority: Authority.READ_PROJECT, - prisma: this.prisma - })) != null - - return allowed - }) + const forksAllowed = forks.filter(async (fork) => { + const allowed = + (await this.authorityCheckerService.checkAuthorityOverProject({ + userId: user.id, + entity: { id: fork.id }, + authority: Authority.READ_PROJECT, + prisma: this.prisma + })) != null + + return allowed + }) + + const items = forksAllowed.slice(page * limit, (page + 1) * limit) + //calculate metadata + const metadata = paginate( + forksAllowed.length, + `/project/${projectId}/forks`, + { + page: Number(page), + limit: Number(limit) + } + ) + + return { items, metadata } } async getProjectById(user: User, projectId: Project['id']) { @@ -638,10 +650,11 @@ export class ProjectService { prisma: this.prisma }) - return ( + //fetch projects with required properties + const items = ( await this.prisma.project.findMany({ skip: page * limit, - take: limit, + take: Number(limit), orderBy: { [sort]: order }, @@ -669,6 +682,42 @@ export class ProjectService { } }) ).map((project) => excludeFields(project, 'privateKey', 'publicKey')) + + //calculate metadata + const totalCount = await this.prisma.project.count({ + where: { + workspaceId, + OR: [ + { + name: { + contains: search + } + }, + { + description: { + contains: search + } + } + ], + workspace: { + members: { + some: { + userId: user.id + } + } + } + } + }) + + const metadata = paginate(totalCount, `/project/all/${workspaceId}`, { + page: Number(page), + limit: Number(limit), + sort, + order, + search + }) + + return { items, metadata } } private async projectExists(