diff --git a/src/proposals/proposals.controller.ts b/src/proposals/proposals.controller.ts index e6c1d7b8b..d95cb1e03 100644 --- a/src/proposals/proposals.controller.ts +++ b/src/proposals/proposals.controller.ts @@ -54,8 +54,10 @@ import { import { plainToInstance } from "class-transformer"; import { validate, ValidatorOptions } from "class-validator"; import { + CountApiResponse, filterDescription, filterExample, + FullFacetFilters, FullFacetResponse, fullQueryExampleLimits, FullQueryFilters, @@ -368,6 +370,38 @@ export class ProposalsController { return this.proposalsService.findAll(proposalFilters); } + // GET /proposals/count + @UseGuards(PoliciesGuard) + @CheckPolicies("proposals", (ability: AppAbility) => + ability.can(Action.ProposalsRead, ProposalClass), + ) + @Get("/count") + @ApiOperation({ + summary: "It returns the number of proposals.", + description: + "It returns a number of proposals matching the where filter if provided.", + }) + @ApiQuery({ + name: "filters", + description: + "Database filters to apply when retrieving count for proposals", + required: false, + type: String, + example: '{"where": {"proposalId": "189691"}}', + }) + @ApiResponse({ + status: 200, + type: CountApiResponse, + description: + "Return the number of proposals in the following format: { count: integer }", + }) + async count(@Req() request: Request, @Query("filters") filters?: string) { + const proposalFilters: IFilters = + this.updateFiltersForList(request, JSON.parse(filters ?? "{}")); + + return this.proposalsService.count(proposalFilters); + } + // GET /proposals/fullquery @UseGuards(PoliciesGuard) @CheckPolicies("proposals", (ability: AppAbility) => @@ -454,7 +488,7 @@ export class ProposalsController { "Full facet query filters to apply when retrieving proposals\n" + proposalsFullQueryDescriptionFields, required: false, - type: String, + type: FullFacetFilters, example: proposalsFullQueryExampleFields, }) @ApiResponse({ diff --git a/src/proposals/proposals.service.ts b/src/proposals/proposals.service.ts index 09258fdc0..7509798df 100644 --- a/src/proposals/proposals.service.ts +++ b/src/proposals/proposals.service.ts @@ -57,6 +57,16 @@ export class ProposalsService { .exec(); } + async count( + filter: IFilters, + ): Promise<{ count: number }> { + const whereFilter: FilterQuery = filter.where ?? {}; + + const count = await this.proposalModel.countDocuments(whereFilter).exec(); + + return { count }; + } + async fullquery( filter: IFilters, ): Promise { diff --git a/test/Proposal.js b/test/Proposal.js index e74155869..2ad0858af 100644 --- a/test/Proposal.js +++ b/test/Proposal.js @@ -176,6 +176,32 @@ describe("1500: Proposal: Simple Proposal", () => { }); }); + it("0091: should get proposal count", async () => { + return request(appUrl) + .get("/api/v3/Proposals/count") + .set({ Authorization: `Bearer ${accessTokenProposalIngestor}` }) + .set("Accept", "application/json") + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body["count"].should.be.greaterThan(0); + }); + }); + + it("0091: should get proposal count using filters", async () => { + const query = { where: { proposalId: { $in: [proposalId] } } }; + return request(appUrl) + .get("/api/v3/Proposals/count") + .set({ Authorization: `Bearer ${accessTokenProposalIngestor}` }) + .query("filter=" + encodeURIComponent(JSON.stringify(query))) + .set("Accept", "application/json") + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body["count"].should.be.equal(1); + }); + }); + it("0100: should add a new attachment to this proposal", async () => { let testAttachment = { ...TestData.AttachmentCorrect }; testAttachment.proposalId = defaultProposalId;