From 70181db7af1d492b9a8f498db3a91b3df29c9b92 Mon Sep 17 00:00:00 2001 From: OJisMe Date: Mon, 12 Feb 2024 18:03:08 -0500 Subject: [PATCH 1/6] feat: getAllAplications endpoint resolves #44 --- .../applications/applications.controller.ts | 17 +++++++++++++ .../src/applications/applications.service.ts | 24 ++++++++++++++++++- apps/backend/src/applications/dto/cycle.ts | 2 +- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/applications/applications.controller.ts b/apps/backend/src/applications/applications.controller.ts index ea20a72..e522083 100644 --- a/apps/backend/src/applications/applications.controller.ts +++ b/apps/backend/src/applications/applications.controller.ts @@ -8,6 +8,7 @@ import { UseGuards, BadRequestException, NotFoundException, + UnauthorizedException, } from '@nestjs/common'; import { CurrentUserInterceptor } from '../interceptors/current-user.interceptor'; import { AuthGuard } from '@nestjs/passport'; @@ -22,6 +23,22 @@ import { UserStatus } from '../users/types'; export class ApplicationsController { constructor(private readonly applicationsService: ApplicationsService) {} + @Get('/') + async getApplications(@Request() req): Promise { + if ( + !( + req.user.status === UserStatus.RECRUITER || + req.user.status === UserStatus.ADMIN + ) + ) { + throw new UnauthorizedException( + 'calling user is not a recruiter or admin', + ); + } + + return this.applicationsService.findAllCurrentApplications(); + } + @Get('/:userId') async getApplication( @Param('userId', ParseIntPipe) userId: number, diff --git a/apps/backend/src/applications/applications.service.ts b/apps/backend/src/applications/applications.service.ts index af2adc4..dbf0b9e 100644 --- a/apps/backend/src/applications/applications.service.ts +++ b/apps/backend/src/applications/applications.service.ts @@ -3,7 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { MongoRepository } from 'typeorm'; import { UsersService } from '../users/users.service'; import { Application } from './application.entity'; -import { getAppForCurrentCycle } from './utils'; +import { getAppForCurrentCycle, getCurrentCycle } from './utils'; +import { GetApplicationResponseDTO } from './dto/get-application.response.dto'; +import { Cycle } from './dto/cycle'; @Injectable() export class ApplicationsService { @@ -22,6 +24,26 @@ export class ApplicationsService { return apps; } + async findAllCurrentApplications(): Promise { + const currentCycle: Cycle = getCurrentCycle(); + const applications = await this.applicationsRepository.find({ + where: { + //TODO q: I had to change Cycle definition to make year and semester public. Is there a reason it was private? + year: currentCycle.year, + semester: currentCycle.semester, + }, + }); + + const dtos: GetApplicationResponseDTO[] = []; + + applications.forEach((app) => + //TODO q: what is the numApps parameter? I just passed 0 in + dtos.push(app.toGetApplicationResponseDTO(0)), + ); + + return dtos; + } + async findCurrent(userId: number): Promise { const apps = await this.findAll(userId); const currentApp = getAppForCurrentCycle(apps); diff --git a/apps/backend/src/applications/dto/cycle.ts b/apps/backend/src/applications/dto/cycle.ts index 4f37b65..6a0580d 100644 --- a/apps/backend/src/applications/dto/cycle.ts +++ b/apps/backend/src/applications/dto/cycle.ts @@ -1,7 +1,7 @@ import { Semester } from '../types'; export class Cycle { - constructor(private year: number, private semester: Semester) {} + constructor(public year: number, public semester: Semester) {} public isCurrentCycle(cycle: Cycle): boolean { return this.year === cycle.year && this.semester === cycle.semester; From 1baee6a6796cbab4f8ae412af070f677ac5c5263 Mon Sep 17 00:00:00 2001 From: OJisMe Date: Sun, 10 Mar 2024 17:30:17 -0400 Subject: [PATCH 2/6] made Cycle fields private, and created env vars for year/semester --- .../src/applications/applications.controller.ts | 2 +- .../backend/src/applications/applications.service.ts | 12 +++++++----- apps/backend/src/applications/dto/cycle.ts | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/backend/src/applications/applications.controller.ts b/apps/backend/src/applications/applications.controller.ts index e522083..cb8e2be 100644 --- a/apps/backend/src/applications/applications.controller.ts +++ b/apps/backend/src/applications/applications.controller.ts @@ -32,7 +32,7 @@ export class ApplicationsController { ) ) { throw new UnauthorizedException( - 'calling user is not a recruiter or admin', + 'Calling user is not a recruiter or admin.', ); } diff --git a/apps/backend/src/applications/applications.service.ts b/apps/backend/src/applications/applications.service.ts index dbf0b9e..2046131 100644 --- a/apps/backend/src/applications/applications.service.ts +++ b/apps/backend/src/applications/applications.service.ts @@ -25,20 +25,22 @@ export class ApplicationsService { } async findAllCurrentApplications(): Promise { - const currentCycle: Cycle = getCurrentCycle(); const applications = await this.applicationsRepository.find({ where: { //TODO q: I had to change Cycle definition to make year and semester public. Is there a reason it was private? - year: currentCycle.year, - semester: currentCycle.semester, + year: process.env.NX_CURRENT_YEAR, + semester: process.env.NX_CURRENT_SEMESTER, }, }); const dtos: GetApplicationResponseDTO[] = []; - applications.forEach((app) => + applications.forEach(async (app) => //TODO q: what is the numApps parameter? I just passed 0 in - dtos.push(app.toGetApplicationResponseDTO(0)), + { + const apps = await this.findAll(app.user.id); + dtos.push(app.toGetApplicationResponseDTO(apps.length)); + }, ); return dtos; diff --git a/apps/backend/src/applications/dto/cycle.ts b/apps/backend/src/applications/dto/cycle.ts index 6a0580d..4f37b65 100644 --- a/apps/backend/src/applications/dto/cycle.ts +++ b/apps/backend/src/applications/dto/cycle.ts @@ -1,7 +1,7 @@ import { Semester } from '../types'; export class Cycle { - constructor(public year: number, public semester: Semester) {} + constructor(private year: number, private semester: Semester) {} public isCurrentCycle(cycle: Cycle): boolean { return this.year === cycle.year && this.semester === cycle.semester; From 716c5b15dc18edf3a1d32ba1bf5c6fa84431be4e Mon Sep 17 00:00:00 2001 From: Jonathan Chen Date: Thu, 14 Mar 2024 12:35:27 -0400 Subject: [PATCH 3/6] Application Summary DTO --- .../src/applications/application.entity.ts | 18 +++++++++++ .../dto/get-all-application.response.dto.ts | 32 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 apps/backend/src/applications/dto/get-all-application.response.dto.ts diff --git a/apps/backend/src/applications/application.entity.ts b/apps/backend/src/applications/application.entity.ts index a4a540a..e7d3ee6 100644 --- a/apps/backend/src/applications/application.entity.ts +++ b/apps/backend/src/applications/application.entity.ts @@ -17,6 +17,7 @@ import { } from './types'; import { GetApplicationResponseDTO } from './dto/get-application.response.dto'; import { Review } from '../reviews/review.entity'; +import { GetAllApplicationResponseDTO } from './dto/get-all-application.response.dto'; @Entity() export class Application { @@ -62,6 +63,23 @@ export class Application { @IsObject({ each: true }) reviews: Review[]; + toGetAllApplicationResponseDTO(): GetAllApplicationResponseDTO { + const meanRatingAllStages = 0; + const meanRatingSingleStages = 0; + + return { + userId: this.user.id, + firstName: this.user.firstName, + lastName: this.user.lastName, + stage: this.stage, + step: this.step, + position: this.position, + createdAt: this.createdAt, + meanRatingAllStages: meanRatingAllStages, + meanRatingSingleStages: meanRatingSingleStages, + }; + } + toGetApplicationResponseDTO(numApps: number): GetApplicationResponseDTO { return { id: this.id, diff --git a/apps/backend/src/applications/dto/get-all-application.response.dto.ts b/apps/backend/src/applications/dto/get-all-application.response.dto.ts new file mode 100644 index 0000000..5ed0264 --- /dev/null +++ b/apps/backend/src/applications/dto/get-all-application.response.dto.ts @@ -0,0 +1,32 @@ +import { IsDate, IsEnum, IsPositive, IsString } from 'class-validator'; +import { ApplicationStage, ApplicationStep, Position } from '../types'; + +export class GetAllApplicationResponseDTO { + @IsPositive() + userId: number; + + @IsString() + firstName: string; + + @IsString() + lastName: string; + + @IsEnum(ApplicationStage) + stage: ApplicationStage; + + @IsEnum(ApplicationStep) + step: ApplicationStep; + + @IsEnum(Position) + position: Position; + + @IsDate() + createdAt: Date; + + @IsPositive() + meanRatingAllStages: number; + + // TODO: Should be a JSON or similar that defines scores for each stage + @IsPositive() + meanRatingSingleStages: number; +} From 3f7f814abd6fccb53c3943657d81190e5c344587 Mon Sep 17 00:00:00 2001 From: Harrison Kim Date: Sun, 17 Mar 2024 15:23:37 -0400 Subject: [PATCH 4/6] feat: completed getAllApplications endpoint --- apps/backend/src/app.module.ts | 1 - .../src/applications/application.entity.ts | 4 +-- .../applications/applications.controller.ts | 6 +++- .../src/applications/applications.service.ts | 29 ++++++++++--------- apps/backend/src/applications/utils.ts | 16 ++++++++-- 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 986ae34..a47cebe 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -13,7 +13,6 @@ import { ApplicationsModule } from './applications/applications.module'; imports: [ TypeOrmModule.forRoot({ type: 'postgres', - database: 'c4c-ops', host: process.env.NX_DB_HOST, port: 5432, username: process.env.NX_DB_USERNAME, diff --git a/apps/backend/src/applications/application.entity.ts b/apps/backend/src/applications/application.entity.ts index 947db5f..c59ceb8 100644 --- a/apps/backend/src/applications/application.entity.ts +++ b/apps/backend/src/applications/application.entity.ts @@ -64,8 +64,8 @@ export class Application { reviews: Review[]; toGetAllApplicationResponseDTO(): GetAllApplicationResponseDTO { - const meanRatingAllStages = 0; - const meanRatingSingleStages = 0; + const meanRatingAllStages = 0; // TODO: calculate this + const meanRatingSingleStages = 0; // TODO: calculate this (should be an object) return { userId: this.user.id, diff --git a/apps/backend/src/applications/applications.controller.ts b/apps/backend/src/applications/applications.controller.ts index 66428fe..a8c894a 100644 --- a/apps/backend/src/applications/applications.controller.ts +++ b/apps/backend/src/applications/applications.controller.ts @@ -20,6 +20,7 @@ import { GetApplicationResponseDTO } from './dto/get-application.response.dto'; import { getAppForCurrentCycle } from './utils'; import { UserStatus } from '../users/types'; import { Application } from './application.entity'; +import { GetAllApplicationResponseDTO } from './dto/get-all-application.response.dto'; @Controller('apps') @UseInterceptors(CurrentUserInterceptor) @@ -39,8 +40,11 @@ export class ApplicationsController { return await this.applicationsService.submitApp(application, user); } + @UseGuards(AuthGuard('jwt')) @Get('/') - async getApplications(@Request() req): Promise { + async getApplications( + @Request() req, + ): Promise { if ( !( req.user.status === UserStatus.RECRUITER || diff --git a/apps/backend/src/applications/applications.service.ts b/apps/backend/src/applications/applications.service.ts index 27d8526..2a23678 100644 --- a/apps/backend/src/applications/applications.service.ts +++ b/apps/backend/src/applications/applications.service.ts @@ -7,12 +7,17 @@ import { InjectRepository } from '@nestjs/typeorm'; import { MongoRepository } from 'typeorm'; import { UsersService } from '../users/users.service'; import { Application } from './application.entity'; -import { getAppForCurrentCycle, getCurrentCycle } from './utils'; -import { GetApplicationResponseDTO } from './dto/get-application.response.dto'; +import { + getAppForCurrentCycle, + getCurrentCycle, + getCurrentSemester, + getCurrentYear, +} from './utils'; import { Response } from './types'; import * as crypto from 'crypto'; import { User } from '../users/user.entity'; import { Position, ApplicationStage, ApplicationStep } from './types'; +import { GetAllApplicationResponseDTO } from './dto/get-all-application.response.dto'; @Injectable() export class ApplicationsService { @@ -98,24 +103,20 @@ export class ApplicationsService { return apps; } - async findAllCurrentApplications(): Promise { + async findAllCurrentApplications(): Promise { const applications = await this.applicationsRepository.find({ where: { - //TODO q: I had to change Cycle definition to make year and semester public. Is there a reason it was private? - year: process.env.NX_CURRENT_YEAR, - semester: process.env.NX_CURRENT_SEMESTER, + year: getCurrentYear(), + semester: getCurrentSemester(), }, + relations: ['user'], }); - const dtos: GetApplicationResponseDTO[] = []; + const dtos: GetAllApplicationResponseDTO[] = []; - applications.forEach(async (app) => - //TODO q: what is the numApps parameter? I just passed 0 in - { - const apps = await this.findAll(app.user.id); - dtos.push(app.toGetApplicationResponseDTO(apps.length)); - }, - ); + applications.forEach((app) => { + dtos.push(app.toGetAllApplicationResponseDTO()); + }); return dtos; } diff --git a/apps/backend/src/applications/utils.ts b/apps/backend/src/applications/utils.ts index 6b45bf8..2a9c10c 100644 --- a/apps/backend/src/applications/utils.ts +++ b/apps/backend/src/applications/utils.ts @@ -2,8 +2,20 @@ import { Application } from './application.entity'; import { Cycle } from './dto/cycle'; import { Semester } from './types'; -// TODO get the current cycle's year and semester from env variables -export const getCurrentCycle = () => new Cycle(2024, Semester.SPRING); +export const getCurrentSemester = (): Semester => { + const month: number = new Date().getMonth(); + if (month >= 0 && month <= 5) { + return Semester.SPRING; + } + return Semester.FALL; +}; + +export const getCurrentYear = (): number => { + return new Date().getFullYear(); +}; + +export const getCurrentCycle = () => + new Cycle(getCurrentYear(), getCurrentSemester()); export const getAppForCurrentCycle = ( applications: Application[], From 463171d2f1a2b92d4bca3b5181ad3862df40f3c9 Mon Sep 17 00:00:00 2001 From: Harrison Kim Date: Sun, 17 Mar 2024 15:47:23 -0400 Subject: [PATCH 5/6] fix: updated semester logic --- apps/backend/src/applications/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/applications/utils.ts b/apps/backend/src/applications/utils.ts index 2a9c10c..cbb2c20 100644 --- a/apps/backend/src/applications/utils.ts +++ b/apps/backend/src/applications/utils.ts @@ -5,9 +5,9 @@ import { Semester } from './types'; export const getCurrentSemester = (): Semester => { const month: number = new Date().getMonth(); if (month >= 0 && month <= 5) { - return Semester.SPRING; + return Semester.FALL; // We will be recruiting for the fall semester during Jan - Jun } - return Semester.FALL; + return Semester.SPRING; // We will be recruiting for the spring semester during Jul - Dec }; export const getCurrentYear = (): number => { From e028116d27be9064a808aed72bdbb7c41ff66477 Mon Sep 17 00:00:00 2001 From: Harrison Kim Date: Tue, 19 Mar 2024 16:21:43 -0400 Subject: [PATCH 6/6] fix: updated current semester function and dto mapping --- apps/backend/src/applications/applications.service.ts | 8 +++----- apps/backend/src/applications/utils.ts | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/backend/src/applications/applications.service.ts b/apps/backend/src/applications/applications.service.ts index 2a23678..45868f6 100644 --- a/apps/backend/src/applications/applications.service.ts +++ b/apps/backend/src/applications/applications.service.ts @@ -112,11 +112,9 @@ export class ApplicationsService { relations: ['user'], }); - const dtos: GetAllApplicationResponseDTO[] = []; - - applications.forEach((app) => { - dtos.push(app.toGetAllApplicationResponseDTO()); - }); + const dtos: GetAllApplicationResponseDTO[] = applications.map((app) => + app.toGetAllApplicationResponseDTO(), + ); return dtos; } diff --git a/apps/backend/src/applications/utils.ts b/apps/backend/src/applications/utils.ts index cbb2c20..b24a353 100644 --- a/apps/backend/src/applications/utils.ts +++ b/apps/backend/src/applications/utils.ts @@ -4,10 +4,10 @@ import { Semester } from './types'; export const getCurrentSemester = (): Semester => { const month: number = new Date().getMonth(); - if (month >= 0 && month <= 5) { - return Semester.FALL; // We will be recruiting for the fall semester during Jan - Jun + if (month >= 1 && month <= 7) { + return Semester.FALL; // We will be recruiting for the fall semester during Feb - Aug } - return Semester.SPRING; // We will be recruiting for the spring semester during Jul - Dec + return Semester.SPRING; // We will be recruiting for the spring semester during Sep - Jan }; export const getCurrentYear = (): number => {