From 7dc9b9b0a75f0999f618d336f2abd3926b9122c8 Mon Sep 17 00:00:00 2001 From: Georgi Parlakov Date: Sun, 23 Jun 2024 14:31:56 +0300 Subject: [PATCH] chore: campaign application create contract (#648) --- apps/api/src/app/app.module.ts | 2 + .../campaign-application.controller.spec.ts | 2 +- .../campaign-application.controller.ts | 21 +++- .../campaign-application.service.ts | 4 + .../dto/create-campaign-application.dto.ts | 113 +++++++++++++++--- podkrepi.dbml | 2 + 6 files changed, 123 insertions(+), 21 deletions(-) diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 833f2aee..ea73ef22 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -62,6 +62,7 @@ import { AffiliateModule } from '../affiliate/affiliate.module' import { LoggerModule } from '../logger/logger.module' import { PrismaModule } from '../prisma/prisma.module' +import { CampaignApplicationModule } from '../campaign-application/campaign-application.module' @Module({ imports: [ @@ -127,6 +128,7 @@ import { PrismaModule } from '../prisma/prisma.module' CampaignNewsFileModule, MarketingNotificationsModule, LoggerModule, + CampaignApplicationModule, ], controllers: [AppController], providers: [ 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 37bc44cd..8f0be134 100644 --- a/apps/api/src/campaign-application/campaign-application.controller.spec.ts +++ b/apps/api/src/campaign-application/campaign-application.controller.spec.ts @@ -63,7 +63,7 @@ describe('CampaignApplicationController', () => { it('when update called it should delegate to the service update', () => { // arrange // act - controller.update('1', {}) + controller.update('1', {}, { sub: 'test', 'allowed-origins': ['test'] }) // assert expect(service.update).toHaveBeenCalledWith('1', {}) diff --git a/apps/api/src/campaign-application/campaign-application.controller.ts b/apps/api/src/campaign-application/campaign-application.controller.ts index 4efdbc6d..7f13109f 100644 --- a/apps/api/src/campaign-application/campaign-application.controller.ts +++ b/apps/api/src/campaign-application/campaign-application.controller.ts @@ -1,31 +1,42 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common' +import { Controller, Get, Post, Body, Patch, Param } 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 { RealmViewSupporters, ViewSupporters } from '@podkrepi-bg/podkrepi-types' +import { KeycloakTokenParsed, isAdmin } from '../auth/keycloak' +@ApiTags('campaign-application') @Controller('campaign-application') export class CampaignApplicationController { constructor(private readonly campaignApplicationService: CampaignApplicationService) {} - @Post() + @Post('create') + @Public() create(@Body() createCampaignApplicationDto: CreateCampaignApplicationDto) { return this.campaignApplicationService.create(createCampaignApplicationDto) } - @Get() + @Get('list') findAll() { return this.campaignApplicationService.findAll() } - @Get(':id') + @Get('byId/:id') findOne(@Param('id') id: string) { return this.campaignApplicationService.findOne(id) } @Patch(':id') - update( + @Roles({ + roles: [RealmViewSupporters.role, ViewSupporters.role], + mode: RoleMatchingMode.ANY, + }) + async update( @Param('id') id: string, @Body() updateCampaignApplicationDto: UpdateCampaignApplicationDto, + @AuthenticatedUser() user: KeycloakTokenParsed, ) { return this.campaignApplicationService.update(id, updateCampaignApplicationDto) } diff --git a/apps/api/src/campaign-application/campaign-application.service.ts b/apps/api/src/campaign-application/campaign-application.service.ts index a3964cc5..296c03a8 100644 --- a/apps/api/src/campaign-application/campaign-application.service.ts +++ b/apps/api/src/campaign-application/campaign-application.service.ts @@ -4,6 +4,10 @@ import { UpdateCampaignApplicationDto } from './dto/update-campaign-application. @Injectable() export class CampaignApplicationService { + async getCampaignByIdWithPersonIds(id: string): Promise { + throw new Error('Method not implemented.') + } + create(createCampaignApplicationDto: CreateCampaignApplicationDto) { return 'This action adds a new campaignApplication' } diff --git a/apps/api/src/campaign-application/dto/create-campaign-application.dto.ts b/apps/api/src/campaign-application/dto/create-campaign-application.dto.ts index 1e3fe9a9..69ad1ebc 100644 --- a/apps/api/src/campaign-application/dto/create-campaign-application.dto.ts +++ b/apps/api/src/campaign-application/dto/create-campaign-application.dto.ts @@ -1,38 +1,121 @@ import { ApiProperty } from '@nestjs/swagger' -import { Prisma } from '@prisma/client' +import { CampaignTypeCategory, Prisma } from '@prisma/client' import { Expose } from 'class-transformer' -import { IsString } from 'class-validator' +import { IsBoolean, IsOptional, IsString } from 'class-validator' @Expose() export class CreateCampaignApplicationDto { + /** + * What would the campaign be called. ('Help Vesko' or 'Castrate Plovdiv Cats') + */ @ApiProperty() @Expose() @IsString() - title: string + campaignName: string + /** user needs to agree to this as a prerequisite to creating a campaign application */ @ApiProperty() @Expose() - acceptTermsAndConditions: boolean + @IsBoolean() + acceptTermsAndConditions: true + /** user needs to agree to this as a prerequisite to creating a campaign application */ @ApiProperty() @Expose() - transparencyTermsAccepted: boolean + @IsBoolean() + transparencyTermsAccepted: true + /** user needs to agree to this as a prerequisite to creating a campaign application */ @ApiProperty() @Expose() - personalInformationProcessingAccepted: boolean + @IsBoolean() + personalInformationProcessingAccepted: true + + /** Who is organizing this campaign */ + @ApiProperty() + @Expose() + @IsString() + organizerName: string + + /** Contact Email to use for the Campaign Application process i.e. if more documents or other info are requested */ + @ApiProperty() + @Expose() + @IsString() + organizerEmail: string + + /** Contact Email to use for the Campaign Application process i.e. if more documents or other info are requested */ + @ApiProperty() + @Expose() + @IsString() + organizerPhone: string + + /** Who will benefit and use the collected donations */ + @ApiProperty() + @Expose() + @IsString() + beneficiary: string + + /** What is the relationship between the Organizer and the Beneficiary ('They're my elderly relative and I'm helping with the internet-computer stuff') */ + @ApiProperty() + @Expose() + @IsString() + organizerBeneficiaryRel: string + + /** What is the result that the collected donations will help achieve */ + @ApiProperty() + @Expose() + @IsString() + goal: string + + /** What if anything has been done so far */ + @ApiProperty() + @Expose() + @IsString() + @IsOptional() + history?: string + + /** How much would the campaign be looking for i.e '10000lv or 5000 Eur or $5000' */ + @ApiProperty() + @Expose() + @IsString() + amount: string + + /** Describe the goal of the campaign in more details */ + @ApiProperty() + @Expose() + @IsString() + @IsOptional() + description?: string + + /** Describe public figures that will back the campaign and help popularize it. */ + @ApiProperty() + @Expose() + @IsString() + @IsOptional() + campaignGuarantee?: string + + /** If any - describe what other sources were used to gather funds for the goal */ + @ApiProperty() + @Expose() + @IsString() + @IsOptional() + otherFinanceSources?: string + + /** Anything that the operator needs to know about the campaign */ + @ApiProperty() + @Expose() + @IsString() + @IsOptional() + otherNotes?: string + + @ApiProperty({ enum: CampaignTypeCategory }) + @Expose() + @IsOptional() + category?: CampaignTypeCategory public toEntity(): Prisma.CampaignApplicationCreateInput { return { - campaignName: this.title, - amount: '', - beneficiary: '', - goal: '', - organizerBeneficiaryRel: '', - organizerName: '', - category: 'others', - organizer: { connect: { id: 'id', personId: '' } }, - documents: { connect: [{ id: '1' }] }, + ...this, } } } diff --git a/podkrepi.dbml b/podkrepi.dbml index 30dc8acd..570b5b70 100644 --- a/podkrepi.dbml +++ b/podkrepi.dbml @@ -600,6 +600,8 @@ Table campaign_applications { category CampaignTypeCategory [default: 'others'] ticketURL String archived Boolean [default: false] + + Note: 'CampaignApplication represents a request for a new campaign - it is not a Campaign yet and has to proove it needs to be' } Table campaign_application_files {