Skip to content

Commit

Permalink
feat upd recruitment-session: service, controller, entity
Browse files Browse the repository at this point in the history
  • Loading branch information
whiitex committed Dec 28, 2023
1 parent 7014267 commit 97aa948
Show file tree
Hide file tree
Showing 8 changed files with 308 additions and 174 deletions.
51 changes: 28 additions & 23 deletions api/src/recruitment-session/create-recruitment-session.dto.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import { RecruitmentSession, RecruitmentSessionState } from "@hkrecruitment/shared/recruitment-session";
import {
RecruitmentSession,
RecruitmentSessionState,
} from '@hkrecruitment/shared/recruitment-session';
import { ApiProperty } from '@nestjs/swagger';

export class CreateRecruitmentSessionDto implements RecruitmentSession {
@ApiProperty()
state: RecruitmentSessionState;

@ApiProperty()
slotDuration: number;

@ApiProperty()
interviewStart: Date;

@ApiProperty()
interviewEnd: Date;

@ApiProperty()
days: [Date];

@ApiProperty()
createdAt: Date;

@ApiProperty()
lastModified: Date;
}
export class CreateRecruitmentSessionDto
implements Partial<RecruitmentSession>
{
//@ApiProperty()
//state: RecruitmentSessionState;

@ApiProperty()
slotDuration: number;

@ApiProperty()
interviewStart: Date;

@ApiProperty()
interviewEnd: Date;

@ApiProperty()
days: [Date];

// @ApiProperty()
// createdAt: Date;

// @ApiProperty()
// lastModified: Date;
}
14 changes: 9 additions & 5 deletions api/src/recruitment-session/recruitment-session-response.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { RecruitmentSession, RecruitmentSessionState } from '@hkrecruitment/shared/recruitment-session';
import {
RecruitmentSession,
RecruitmentSessionState,
} from '@hkrecruitment/shared/recruitment-session';
import { Exclude, Expose } from 'class-transformer';

@Exclude()
export class RecruitmentSessionResponseDto implements Partial<RecruitmentSession> {
@Expose() id: number;
@Expose() createdAt: Date;
export class RecruitmentSessionResponseDto
implements Partial<RecruitmentSession>
{
@Expose() id: number;
@Expose() createdAt: Date;
}

237 changes: 158 additions & 79 deletions api/src/recruitment-session/recruitment-session.controller.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import {
Body,
Controller,
BadRequestException,
NotFoundException,
ConflictException,
Param,
Post,
Delete,
Req,
Patch,
ForbiddenException,
} from '@nestjs/common';
Body,
Controller,
BadRequestException,
NotFoundException,
ConflictException,
Param,
Post,
Delete,
Req,
Patch,
ForbiddenException,
} from '@nestjs/common';
import { RecruitmentSessionService } from './recruitment-session.service';
import { createRecruitmentSessionSchema, RecruitmentSession, RecruitmentSessionState, updateRecruitmentSessionSchema } from '@hkrecruitment/shared/recruitment-session';
import { Action, AppAbility, checkAbility } from "@hkrecruitment/shared"
import {
createRecruitmentSessionSchema,
RecruitmentSession,
RecruitmentSessionState,
updateRecruitmentSessionSchema,
} from '@hkrecruitment/shared/recruitment-session';
import { Action, AppAbility, checkAbility } from '@hkrecruitment/shared';
import { JoiValidate } from '../joi-validation/joi-validate.decorator';
import {
ApiBadRequestResponse,
ApiBearerAuth,
ApiForbiddenResponse,
ApiNotFoundResponse,
ApiCreatedResponse,
ApiOkResponse,
ApiTags,
ApiConflictResponse,
ApiNoContentResponse,
ApiBadRequestResponse,
ApiBearerAuth,
ApiForbiddenResponse,
ApiNotFoundResponse,
ApiCreatedResponse,
ApiOkResponse,
ApiTags,
ApiConflictResponse,
ApiNoContentResponse,
} from '@nestjs/swagger';
import { CheckPolicies } from 'src/authorization/check-policies.decorator';
import { CreateRecruitmentSessionDto } from './create-recruitment-session.dto';
Expand All @@ -39,64 +44,138 @@ import { RecruitmentSessionResponseDto } from './recruitment-session-response.dt
@ApiTags('recruitment-session')
@Controller('recruitment-session')
export class RecruitmentSessionController {
constructor(private readonly recruitmentSessionService: RecruitmentSessionService) {}

// CREATE NEW RECRUITMENT SESSION
@ApiBadRequestResponse()
@ApiForbiddenResponse()
@ApiConflictResponse({
description: 'The recruitment session cannot be created', //
})
@ApiCreatedResponse()
@JoiValidate({
body: createRecruitmentSessionSchema,
})
@CheckPolicies((ability) => ability.can(Action.Create, 'RecruitmentSession'))
@Post()
async createRecruitmentSession(@Body() rSess: CreateRecruitmentSessionDto): Promise<RecruitmentSession> {
return this.recruitmentSessionService.createRecruitmentSession({...rSess});
}
constructor(
private readonly recruitmentSessionService: RecruitmentSessionService,
) {}

// UPDATE A RECRUITMENT SESSION
@Patch(':session_id')
@ApiBadRequestResponse()
@ApiForbiddenResponse()
@ApiOkResponse()
@JoiValidate({
param: Joi.number().positive().integer().required().label('session_id'),
body: updateRecruitmentSessionSchema,
})
async updateRecruitmentSession(
@Param('session_id') sessionId: number,
@Body() updateRecruitmentSession: UpdateRecruitmentSessionDto,
@Ability() ability: AppAbility,
@Req() req: AuthenticatedRequest,
): Promise<RecruitmentSessionResponseDto> {
const session = await this.recruitmentSessionService.findRecruitmentSessionById(sessionId);

if (session === null) throw new NotFoundException();

const sessionToCheck = {
...updateRecruitmentSession,
sessionId: session.id,
};
if (
!checkAbility(ability, Action.Update, sessionToCheck, 'RecruitmentSession', [
'applicantId',
])
// CREATE NEW RECRUITMENT SESSION
@ApiBadRequestResponse()
@ApiForbiddenResponse()
@ApiConflictResponse({
description: 'The recruitment session cannot be created', //
})
@ApiCreatedResponse()
@JoiValidate({
body: createRecruitmentSessionSchema,
})
@CheckPolicies((ability) => ability.can(Action.Create, 'RecruitmentSession'))
@Post()
async createRecruitmentSession(
@Body() recruitmentSession: CreateRecruitmentSessionDto,
): Promise<RecruitmentSession> {
// there should be only one active recruitment session at a time
const hasActiveRecruitmentSession =
await this.recruitmentSessionService.findActiveRecruitmentSession();
if (hasActiveRecruitmentSession)
throw new ConflictException(
'There is already an active recruitment session',
);

return this.recruitmentSessionService.createRecruitmentSession({
...recruitmentSession,
});
}

// UPDATE A RECRUITMENT SESSION
@Patch(':session_id')
@ApiBadRequestResponse()
@ApiForbiddenResponse()
@ApiOkResponse()
@JoiValidate({
param: Joi.number().positive().integer().required().label('session_id'),
body: updateRecruitmentSessionSchema,
})
async updateRecruitmentSession(
@Param('session_id') sessionId: number,
@Body() updateRecruitmentSession: UpdateRecruitmentSessionDto,
@Ability() ability: AppAbility,
@Req() req: AuthenticatedRequest,
): Promise<RecruitmentSessionResponseDto> {
const recruitmentSession =
await this.recruitmentSessionService.findRecruitmentSessionById(
sessionId,
);

if (recruitmentSession === null) throw new NotFoundException();

const sessionToCheck = {
...updateRecruitmentSession,
sessionId: recruitmentSession.id,
};
if (
!checkAbility(
ability,
Action.Update,
sessionToCheck,
'RecruitmentSession',
['applicantId'],
)
throw new ForbiddenException();

const updatedRecruitmentSession = await this.recruitmentSessionService.updateRecruitmentSession(
{
...session,
...updateRecruitmentSession,
lastModified: new Date(),
},
)
throw new ForbiddenException();

const updatedRecruitmentSession =
await this.recruitmentSessionService.updateRecruitmentSession({
...recruitmentSession,
...updateRecruitmentSession,
lastModified: new Date(),
});

return plainToClass(
RecruitmentSessionResponseDto,
updatedRecruitmentSession,
);
}

// DELETE A RECRUITMENT SESSION BY START & END DATE
@ApiBadRequestResponse()
@ApiForbiddenResponse()
@ApiNotFoundResponse()
@ApiOkResponse()
@ApiNoContentResponse()
@CheckPolicies((ability) => ability.can(Action.Delete, 'RecruitmentSession'))
// @Delete('/:time_slot_id')
// @JoiValidate({
// param: Joi.number().positive().integer().required().label('time_slot_id'),
// })
async deleteTimeSlotByStartEnd(
@Param('start') startDate: Date,
@Param('end') endDate: Date,
): Promise<RecruitmentSession> {
const toRemove =
await this.recruitmentSessionService.findRecruitmentSessionByStartEndDate(
startDate,
endDate,
);

return plainToClass(RecruitmentSessionResponseDto, updatedRecruitmentSession);
}
if (!toRemove) throw new NotFoundException('Recruitment session not found');
return await this.recruitmentSessionService.deletRecruitmentSession(
toRemove,
);
}

// DELETE A RECRUITMENT SESSION
@ApiBadRequestResponse()
@ApiForbiddenResponse()
@ApiNotFoundResponse()
@ApiOkResponse()
@ApiNoContentResponse()
@CheckPolicies((ability) => ability.can(Action.Delete, 'RecruitmentSession'))
@Delete('/:recruitment_session_id')
@JoiValidate({
param: Joi.number().positive().integer().required().label('time_slot_id'),
})
async deleteTimeSlotById(
@Param('recruitment_session_id') recruitmentSessionId: number,
): Promise<RecruitmentSession> {
// check if it exists
const toRemove =
await this.recruitmentSessionService.findRecruitmentSessionById(
recruitmentSessionId,
);
if (!toRemove) throw new NotFoundException('Recruitment session not found');

}
// delete it
return await this.recruitmentSessionService.deletRecruitmentSession(
toRemove,
);
}
}
16 changes: 9 additions & 7 deletions api/src/recruitment-session/recruitment-session.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { RecruitmentSession as RecruitmentSessionInterface, RecruitmentSessionState } from '@hkrecruitment/shared/src/recruitment-session'

import {
RecruitmentSession as RecruitmentSessionInterface,
RecruitmentSessionState,
} from '@hkrecruitment/shared/src/recruitment-session';

@Entity()
export class RecruitmentSession implements RecruitmentSessionInterface {
Expand All @@ -10,21 +12,21 @@ export class RecruitmentSession implements RecruitmentSessionInterface {
@Column()
state: RecruitmentSessionState;

@Column()
@Column({ name: 'slot_duration' })
slotDuration: number;

@Column()
@Column({ name: 'interview_start' })
interviewStart: Date;

@Column()
@Column({ name: 'interview_end' })
interviewEnd: Date;

@Column()
days: [Date];

@Column()
@Column({ name: 'created_at' })
createdAt: Date;

@Column()
@Column({ name: 'last_modified' })
lastModified: Date;
}
Loading

0 comments on commit 97aa948

Please sign in to comment.