Skip to content

Commit

Permalink
Persisting created new campaignApplication to db (#657)
Browse files Browse the repository at this point in the history
* finish create functionality and testing on it

update CampaignApplication model - organizerEmail now is not unique
update create method testing
now created campaig-application data is persisted to db

* finish create functionality and testing on it

update CampaignApplication model - organizerEmail now is not unique
update create method testing
now created campaig-application data is persisted to db

* restructured mocking of data in service.spec and controller.spec

* finish mocking data changes

* updated controller,spec mockis

* fix module providers

* hardcoded testing values

* delete unused imports & recover unit test

* remove campaingApplication data sanitization

* importing moduls instead of providing services

delete PersonService and OrganizerService and add PersonModule and OrganizersModule to campaign-application module
  • Loading branch information
Martbul authored Jul 17, 2024
1 parent 05bd507 commit d540599
Show file tree
Hide file tree
Showing 12 changed files with 373 additions and 141 deletions.
49 changes: 49 additions & 0 deletions apps/api/src/auth/__mocks__.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { KeycloakTokenParsed } from './keycloak'

export const mockUser = {
exp: 1719866987,
iat: 1719866687,
jti: '607c488f-6e18-4455-8384-161cec4f1940',
iss: 'http://localhost:8180/auth/realms/webapp',
aud: 'account',
sub: '5795ea9e-ac11-436b-b97d-7b03dbd863f2',
typ: 'Bearer',
azp: 'jwt-headless',
session_state: 'def317ff-0043-4509-ade3-926dd155085e',
'allowed-origins': ['*'],
realm_access: { roles: ['default-roles-webapp', 'offline_access', 'uma_authorization'] },
resource_access: {
account: { roles: ['manage-account', 'manage-account-links', 'view-profile'] },
},
scope: 'openid profile email',
sid: 'def317ff-0043-4509-ade3-926dd155085e',
email_verified: 'true',
name: 'asdasd sdfsdfsdfs',
preferred_username: '[email protected]',
given_name: 'asdasd',
family_name: 'sdfsdfsdfs',
email: '[email protected]',
} as KeycloakTokenParsed

export const mockUserAdmin = {
exp: 1719866987,
iat: 1719866687,
jti: '607c488f-6e18-4455-8384-161cec4f1940',
iss: 'http://localhost:8180/auth/realms/webapp',
aud: 'account',
sub: '5795ea9e-ac11-436b-b97d-7b03dbd863f2',
typ: 'Bearer',
azp: 'jwt-headless',
session_state: 'def317ff-0043-4509-ade3-926dd155085e',
'allowed-origins': ['*'],
realm_access: { roles: ['default-roles-webapp', 'offline_access', 'uma_authorization'] },
resource_access: { account: { roles: ['manage-account', 'account-view-supporters'] } },
scope: 'openid profile email',
sid: 'def317ff-0043-4509-ade3-926dd155085e',
email_verified: 'true',
name: 'asdasd sdfsdfsdfs',
preferred_username: '[email protected]',
given_name: 'asdasd',
family_name: 'sdfsdfsdfs',
email: '[email protected]',
} as KeycloakTokenParsed
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { CampaignApplicationState, CampaignTypeCategory } from '@prisma/client'
import { CreateCampaignApplicationDto } from '../dto/create-campaign-application.dto'

export const mockNewCampaignApplication = {
campaignName: 'Test Campaign',
organizerName: 'Test Organizer',
organizerEmail: '[email protected]',
organizerPhone: '123456789',
beneficiary: 'Test beneficary',
organizerBeneficiaryRel: 'Test organizerBeneficiaryRel',
goal: 'Test goal',
history: 'Test history',
amount: '1000',
description: 'Test description',
campaignGuarantee: 'Test guarantee',
otherFinanceSources: 'Test otherFinanceSources',
otherNotes: 'Test otherNotes',
category: CampaignTypeCategory.medical,
}

const dto: CreateCampaignApplicationDto = {

Check warning on line 21 in apps/api/src/campaign-application/__mocks__/campaign-application-mocks.ts

View workflow job for this annotation

GitHub Actions / Run API tests

'dto' is assigned a value but never used
...mockNewCampaignApplication,
acceptTermsAndConditions: true,
transparencyTermsAccepted: true,
personalInformationProcessingAccepted: true,
toEntity: new CreateCampaignApplicationDto().toEntity,
}

export const mockCampaigns = [
{
id: '1',
createdAt: new Date('2022-04-08T06:36:33.661Z'),
updatedAt: new Date('2022-04-08T06:36:33.662Z'),
description: 'Test description1',
organizerId: 'testOrganizerId1',
organizerName: 'Test Organizer1',
organizerEmail: '[email protected]',
beneficiary: 'test beneficary1',
organizerPhone: '123456789',
organizerBeneficiaryRel: 'Test Relation1',
campaignName: 'Test Campaign1',
goal: 'Test Goal1',
history: 'test history1',
amount: '1000',
campaignGuarantee: 'test campaignGuarantee1',
otherFinanceSources: 'test otherFinanceSources1',
otherNotes: 'test otherNotes1',
state: CampaignApplicationState.review,
category: CampaignTypeCategory.medical,
ticketURL: 'testsodifhso1',
archived: false,
},
{
id: '2',
createdAt: new Date('2022-04-08T06:36:33.661Z'),
updatedAt: new Date('2022-04-08T06:36:33.662Z'),
description: 'Test description2',
organizerId: 'testOrganizerId2',
organizerName: 'Test Organizer2',
organizerEmail: '[email protected]',
beneficiary: 'test beneficary2',
organizerPhone: '123456789',
organizerBeneficiaryRel: 'Test Relation2',
campaignName: 'Test Campaign2',
goal: 'Test Goal2',
history: 'test history2',
amount: '1000',
campaignGuarantee: 'test campaignGuarantee2',
otherFinanceSources: 'test otherFinanceSources2',
otherNotes: 'test otherNotes2',
state: CampaignApplicationState.review,
category: CampaignTypeCategory.medical,
ticketURL: 'testsodifhso2',
archived: false,
},
]

export const mockCreatedCampaignApplication = {
id: 'mockCampaignApplicationId',
createdAt: new Date('2022-04-08T06:36:33.661Z'),
updatedAt: new Date('2022-04-08T06:36:33.662Z'),
...mockNewCampaignApplication,
organizerId: 'mockOrganizerId',
state: CampaignApplicationState.review,
ticketURL: null,
archived: false,
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
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')
import { autoSpy } from '@podkrepi-bg/testing'
import { CreateCampaignApplicationDto } from './dto/create-campaign-application.dto'
import { KeycloakTokenParsed } from '../auth/keycloak'
import { ForbiddenException, NotFoundException } from '@nestjs/common'
import { PersonService } from '../person/person.service'
import { mockUser, mockUserAdmin } from './../auth/__mocks__'
import { mockNewCampaignApplication } from './__mocks__/campaign-application-mocks'

describe('CampaignApplicationController', () => {
let controller: CampaignApplicationController
let service: SpyOf<CampaignApplicationService>
let service: CampaignApplicationService
let personService: PersonService

const mockCreateNewCampaignApplication = {
...mockNewCampaignApplication,
acceptTermsAndConditions: true,
transparencyTermsAccepted: true,
personalInformationProcessingAccepted: true,
toEntity: new CreateCampaignApplicationDto().toEntity,
} as CreateCampaignApplicationDto

beforeEach(async () => {
service = autoSpy(CampaignApplicationService)
personService = autoSpy(PersonService)

const module: TestingModule = await Test.createTestingModule({
controllers: [CampaignApplicationController],
providers: [{ provide: CampaignApplicationService, useValue: service }],
providers: [
{ provide: CampaignApplicationService, useValue: service },
{ provide: PersonService, useValue: personService },
],
}).compile()

controller = module.get<CampaignApplicationController>(CampaignApplicationController)
Expand All @@ -26,63 +41,63 @@ describe('CampaignApplicationController', () => {
expect(controller).toBeDefined()
})

it('when create called it should delegate to the service create', () => {
// arrange
// act
controller.create({
acceptTermsAndConditions: true,
personalInformationProcessingAccepted: true,
transparencyTermsAccepted: true,
title: 'new ',
toEntity: jest.fn(),
})

// assert
expect(service.create).toHaveBeenCalledWith({
acceptTermsAndConditions: true,
personalInformationProcessingAccepted: true,
transparencyTermsAccepted: true,
title: 'new ',
toEntity: expect.any(Function),
})
it('when create called it should delegate to the service create', async () => {
// Arrange
jest.spyOn(personService, 'findOneByKeycloakId').mockResolvedValue(mockUser)

// Act
await controller.create(mockCreateNewCampaignApplication, mockUser)

// Assert
expect(service.create).toHaveBeenCalledWith(mockCreateNewCampaignApplication, mockUser)
})

it('when create called with wrong user it should throw NotFoundException', async () => {
jest.spyOn(personService, 'findOneByKeycloakId').mockResolvedValue(null)

// Act & Assert
await expect(controller.create(mockCreateNewCampaignApplication, mockUser)).rejects.toThrow(
NotFoundException,
)
})

it('when findAll called by a non-admin user it should throw a ForbiddenException', () => {
// arrange
jest.mock('../auth/keycloak', () => ({
isAdmin: jest.fn().mockReturnValue(false),
}))

// Arrange
const user = { sub: 'non-admin', 'allowed-origins': ['test'] } as KeycloakTokenParsed
;(isAdmin as jest.Mock).mockReturnValue(false)

// act & assert
// 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(user)

// assert
expect(service.findAll).toHaveBeenCalledWith()
jest.mock('../auth/keycloak', () => ({
isAdmin: jest.fn().mockImplementation((user: KeycloakTokenParsed) => {
return user.resource_access?.account?.roles.includes('account-view-supporters')
}),
}))

// Act & Assert
expect(() => controller.findAll(mockUserAdmin)).not.toThrow(ForbiddenException)
controller.findAll(mockUserAdmin)
expect(service.findAll).toHaveBeenCalled()
})

it('when findOne called it should delegate to the service findOne', () => {
// arrange
// act
// Act
controller.findOne('id')

// assert
// Assert
expect(service.findOne).toHaveBeenCalledWith('id')
})

it('when update called it should delegate to the service update', () => {
// arrange
// act
// Act
controller.update('1', {}, { sub: 'test', 'allowed-origins': ['test'] })

// assert
// Assert
expect(service.update).toHaveBeenCalledWith('1', {})
})
})
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
import { Controller, Get, Post, Body, Patch, Param, ForbiddenException } from '@nestjs/common'
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
ForbiddenException,
NotFoundException,
Logger,
} 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'
import { ApiTags } from '@nestjs/swagger'
import { AuthenticatedUser, Public, RoleMatchingMode, Roles } from 'nest-keycloak-connect'
import { AuthenticatedUser, RoleMatchingMode, Roles } from 'nest-keycloak-connect'
import { RealmViewSupporters, ViewSupporters } from '@podkrepi-bg/podkrepi-types'
import { KeycloakTokenParsed, isAdmin } from '../auth/keycloak'
import { PersonService } from '../person/person.service'

@ApiTags('campaign-application')
@Controller('campaign-application')
export class CampaignApplicationController {
constructor(private readonly campaignApplicationService: CampaignApplicationService) {}
constructor(
private readonly campaignApplicationService: CampaignApplicationService,
private readonly personService: PersonService,
) {}

@Post('create')
@Public()
create(@Body() createCampaignApplicationDto: CreateCampaignApplicationDto) {
return this.campaignApplicationService.create(createCampaignApplicationDto)
async create(
@Body() createCampaignApplicationDto: CreateCampaignApplicationDto,
@AuthenticatedUser() user: KeycloakTokenParsed,
) {
const person = await this.personService.findOneByKeycloakId(user.sub)

if (!person) {
Logger.error('No person found in database')
throw new NotFoundException('No person found in database')
}

return this.campaignApplicationService.create(createCampaignApplicationDto, person)
}

@Get('list')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { Module } from '@nestjs/common'
import { CampaignApplicationService } from './campaign-application.service'
import { CampaignApplicationController } from './campaign-application.controller'
import { PrismaModule } from '../prisma/prisma.module'
import { PersonModule } from '../person/person.module'
import { OrganizerModule } from '../organizer/organizer.module'
@Module({
imports: [PrismaModule],
imports: [PrismaModule, PersonModule, OrganizerModule],
controllers: [CampaignApplicationController],
providers: [CampaignApplicationService],
})
Expand Down
Loading

0 comments on commit d540599

Please sign in to comment.