diff --git a/apps/api/src/campaign-application/campaign-application.controller.spec.ts b/apps/api/src/campaign-application/campaign-application.controller.spec.ts index 8f0be134..21244b12 100644 --- a/apps/api/src/campaign-application/campaign-application.controller.spec.ts +++ b/apps/api/src/campaign-application/campaign-application.controller.spec.ts @@ -2,6 +2,10 @@ import { Test, TestingModule } from '@nestjs/testing' import { CampaignApplicationController } from './campaign-application.controller' import { CampaignApplicationService } from './campaign-application.service' import { SpyOf, autoSpy } from '@podkrepi-bg/testing' +import { ForbiddenException } from '@nestjs/common' +import { KeycloakTokenParsed, isAdmin } from '../auth/keycloak' + +jest.mock('../auth/keycloak') describe('CampaignApplicationController', () => { let controller: CampaignApplicationController @@ -43,14 +47,27 @@ describe('CampaignApplicationController', () => { }) }) - it('when findAll called it should delegate to the service findAll', () => { + it('when findAll called by a non-admin user it should throw a ForbiddenException', () => { // arrange + const user = { sub: 'non-admin', 'allowed-origins': ['test'] } as KeycloakTokenParsed + ;(isAdmin as jest.Mock).mockReturnValue(false) + + // act & assert + expect(() => controller.findAll(user)).toThrow(ForbiddenException) + }) + + it('when findAll called by an admin user it should delegate to the service findAll', () => { + // arrange + const user = { sub: 'admin', 'allowed-origins': ['test'] } as KeycloakTokenParsed + ;(isAdmin as jest.Mock).mockReturnValue(true) + // act - controller.findAll() + controller.findAll(user) // assert expect(service.findAll).toHaveBeenCalledWith() }) + it('when findOne called it should delegate to the service findOne', () => { // arrange // act diff --git a/apps/api/src/campaign-application/campaign-application.controller.ts b/apps/api/src/campaign-application/campaign-application.controller.ts index 7f13109f..8a215172 100644 --- a/apps/api/src/campaign-application/campaign-application.controller.ts +++ b/apps/api/src/campaign-application/campaign-application.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Patch, Param } from '@nestjs/common' +import { Controller, Get, Post, Body, Patch, Param, ForbiddenException } from '@nestjs/common' import { CampaignApplicationService } from './campaign-application.service' import { CreateCampaignApplicationDto } from './dto/create-campaign-application.dto' import { UpdateCampaignApplicationDto } from './dto/update-campaign-application.dto' @@ -19,7 +19,10 @@ export class CampaignApplicationController { } @Get('list') - findAll() { + findAll(@AuthenticatedUser() user: KeycloakTokenParsed) { + if (!isAdmin(user)) { + throw new ForbiddenException('Must be admin to get all campaign-applications') + } return this.campaignApplicationService.findAll() } diff --git a/apps/api/src/campaign-application/campaign-application.module.ts b/apps/api/src/campaign-application/campaign-application.module.ts index e574e3f7..0c421d19 100644 --- a/apps/api/src/campaign-application/campaign-application.module.ts +++ b/apps/api/src/campaign-application/campaign-application.module.ts @@ -1,8 +1,9 @@ import { Module } from '@nestjs/common' import { CampaignApplicationService } from './campaign-application.service' import { CampaignApplicationController } from './campaign-application.controller' - +import { PrismaModule } from '../prisma/prisma.module' @Module({ + imports: [PrismaModule], controllers: [CampaignApplicationController], providers: [CampaignApplicationService], }) diff --git a/apps/api/src/campaign-application/campaign-application.service.spec.ts b/apps/api/src/campaign-application/campaign-application.service.spec.ts index b48a5fb9..11948680 100644 --- a/apps/api/src/campaign-application/campaign-application.service.spec.ts +++ b/apps/api/src/campaign-application/campaign-application.service.spec.ts @@ -1,14 +1,26 @@ import { Test, TestingModule } from '@nestjs/testing' import { CampaignApplicationService } from './campaign-application.service' import { CreateCampaignApplicationDto } from './dto/create-campaign-application.dto' -import { BadRequestException, HttpStatus } from '@nestjs/common' +import { BadRequestException } from '@nestjs/common' +import { CampaignApplicationState, CampaignTypeCategory } from '@prisma/client' +import { prismaMock, MockPrismaService } from '../prisma/prisma-client.mock' +import { EmailService } from '../email/email.service' describe('CampaignApplicationService', () => { let service: CampaignApplicationService beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [CampaignApplicationService], + providers: [ + CampaignApplicationService, + MockPrismaService, + { + provide: EmailService, + useValue: { + sendFromTemplate: jest.fn(() => true), + }, + }, + ], }).compile() service = module.get(CampaignApplicationService) @@ -28,9 +40,10 @@ describe('CampaignApplicationService', () => { organizerBeneficiaryRel: 'Test Relation', goal: 'Test Goal', amount: '1000', - toEntity: jest.fn(), // Mock implementation + toEntity: jest.fn(), } - it('should throw an error if acceptTermsAndConditions are not accepted', () => { + + it('should throw an error if acceptTermsAndConditions is false', () => { const dto: CreateCampaignApplicationDto = { ...baseDto, acceptTermsAndConditions: false, @@ -43,7 +56,7 @@ describe('CampaignApplicationService', () => { ) }) - it('should throw an error if transparencyTermsAccepted are not accepted', () => { + it('should throw an error if transparencyTermsAccepted is false', () => { const dto: CreateCampaignApplicationDto = { ...baseDto, acceptTermsAndConditions: true, @@ -56,7 +69,7 @@ describe('CampaignApplicationService', () => { ) }) - it('should throw an error if personalInformationProcessingAccepted is not accepted', () => { + it('should throw an error if personalInformationProcessingAccepted is false', () => { const dto: CreateCampaignApplicationDto = { ...baseDto, acceptTermsAndConditions: true, @@ -69,7 +82,7 @@ describe('CampaignApplicationService', () => { ) }) - it('should add a new campaign application if all agreements are accepted', () => { + it('should add a new campaign-application if all agreements are true', () => { const dto: CreateCampaignApplicationDto = { ...baseDto, acceptTermsAndConditions: true, @@ -80,4 +93,81 @@ describe('CampaignApplicationService', () => { expect(service.create(dto)).toBe('This action adds a new campaignApplication') }) }) -}) + + describe('findAll', () => { + it('should return an array of campaign-applications', async () => { + const mockCampaigns = [ + { + id: 'testId', + createdAt: new Date('2022-04-08T06:36:33.661Z'), + updatedAt: new Date('2022-04-08T06:36:33.662Z'), + description: 'Test description', + organizerId: 'testOrganizerId1', + organizerName: 'Test Organizer1', + organizerEmail: 'organizer@example.com', + beneficiary: 'test beneficary', + organizerPhone: '123456789', + organizerBeneficiaryRel: 'Test Relation', + campaignName: 'Test Campaign', + goal: 'Test Goal', + history: 'test history', + amount: '1000', + campaignGuarantee: 'test campaignGuarantee', + otherFinanceSources: 'test otherFinanceSources', + otherNotes: 'test otherNotes', + state: CampaignApplicationState.review, + category: CampaignTypeCategory.medical, + ticketURL: 'testsodifhso', + archived: false, + }, + { + id: 'testId2', + createdAt: new Date('2022-04-08T06:36:33.661Z'), + updatedAt: new Date('2022-04-08T06:36:33.662Z'), + description: 'Test description', + organizerId: 'testOrganizerId2', + organizerName: 'Test Organizer2', + organizerEmail: 'organizer2@example.com', + beneficiary: 'test beneficary2', + organizerPhone: '123456789', + organizerBeneficiaryRel: 'Test Relation2', + campaignName: 'Test Campaign2', + goal: 'Test Goal2', + history: 'test history2', + amount: '2000', + campaignGuarantee: 'test campaignGuarantee2', + otherFinanceSources: 'test otherFinanceSources2', + otherNotes: 'test otherNotes2', + state: CampaignApplicationState.review, + category: CampaignTypeCategory.medical, + ticketURL: 'testsodifhso2', + archived: false, + }, + ] + + prismaMock.campaignApplication.findMany.mockResolvedValue(mockCampaigns) + + const result = await service.findAll() + + expect(result).toEqual(mockCampaigns) + expect(prismaMock.campaignApplication.findMany).toHaveBeenCalledTimes(1) + }) + + it('should return an empty array if no campaign-applications are found', async () => { + prismaMock.campaignApplication.findMany.mockResolvedValue([]) + + const result = await service.findAll() + + expect(result).toEqual([]) + expect(prismaMock.campaignApplication.findMany).toHaveBeenCalledTimes(1) + }) + + it('should handle errors and throw an exception', async () => { + const errorMessage = 'error' + prismaMock.campaignApplication.findMany.mockRejectedValue(new Error(errorMessage)) + + await expect(service.findAll()).rejects.toThrow(errorMessage) + expect(prismaMock.campaignApplication.findMany).toHaveBeenCalledTimes(1) + }) + }) +}) \ No newline at end of file diff --git a/apps/api/src/campaign-application/campaign-application.service.ts b/apps/api/src/campaign-application/campaign-application.service.ts index 532bbba1..9b4a0bcc 100644 --- a/apps/api/src/campaign-application/campaign-application.service.ts +++ b/apps/api/src/campaign-application/campaign-application.service.ts @@ -1,9 +1,11 @@ import { BadRequestException, HttpException, HttpStatus, Injectable } from '@nestjs/common' import { CreateCampaignApplicationDto } from './dto/create-campaign-application.dto' import { UpdateCampaignApplicationDto } from './dto/update-campaign-application.dto' +import { PrismaService } from '../prisma/prisma.service' @Injectable() export class CampaignApplicationService { + constructor(private prisma: PrismaService) {} async getCampaignByIdWithPersonIds(id: string): Promise { throw new Error('Method not implemented.') } @@ -20,7 +22,7 @@ export class CampaignApplicationService { } findAll() { - return `This action returns all campaignApplication` + return this.prisma.campaignApplication.findMany() } findOne(id: string) {