diff --git a/src/common/guards/ownership.guard.ts b/src/common/guards/ownership.guard.ts index 9fcba18..27928bc 100644 --- a/src/common/guards/ownership.guard.ts +++ b/src/common/guards/ownership.guard.ts @@ -1,4 +1,4 @@ -import { +import { CanActivate, Injectable, ExecutionContext, @@ -17,15 +17,15 @@ export class OwnershipGuard implements CanActivate { constructor( private reflector: Reflector, private moduleRef: ModuleRef, - ) {} + ) { } - async canActivate(context: ExecutionContext): Promise{ + async canActivate(context: ExecutionContext): Promise { const meta = this.reflector.get( OWNER_KEY, context.getHandler(), ); - if (!meta) + if (!meta) return true; - + const request = context.switchToHttp().getRequest(); const user = request.user; const resourceId = request.params[meta.idParam || 'id']; diff --git a/src/common/guards/roles.guard.ts b/src/common/guards/roles.guard.ts index 61889f7..9a9244d 100644 --- a/src/common/guards/roles.guard.ts +++ b/src/common/guards/roles.guard.ts @@ -17,7 +17,7 @@ interface RequestWithUser extends Request { @Injectable() export class RolesGuard implements CanActivate { - constructor(private reflector: Reflector) {} + constructor(private reflector: Reflector) { } /** * @swagger @@ -37,9 +37,9 @@ export class RolesGuard implements CanActivate { * or returns `false` if the user is not authenticated. */ canActivate(ctx: ExecutionContext): boolean { - const requiredRoles = this.reflector.get( + const requiredRoles = this.reflector.getAllAndOverride( ROLES_KEY, - ctx.getHandler(), + [ctx.getHandler(), ctx.getClass()], ); //for "deny-by-default" when role is wrong or unavailable if (!requiredRoles || requiredRoles.length === 0) { diff --git a/src/common/shared/role-groupes.ts b/src/common/shared/role-groupes.ts new file mode 100644 index 0000000..b67c432 --- /dev/null +++ b/src/common/shared/role-groupes.ts @@ -0,0 +1,15 @@ +import { Roles as RoleEnum } from ".prisma/client"; + +export const GLOBAL_CONTROLLER_ROLES: readonly RoleEnum[] = [ + RoleEnum.EMPLOYEE, + RoleEnum.ACCOUNTING, + RoleEnum.HR, + RoleEnum.SUPERVISOR, + RoleEnum.ADMIN, +]; + +export const MANAGER_ROLES: readonly RoleEnum[] = [ + RoleEnum.HR, + RoleEnum.SUPERVISOR, + RoleEnum.ADMIN, +] \ No newline at end of file diff --git a/src/identity-and-account/employees/controllers/employees.controller.ts b/src/identity-and-account/employees/controllers/employees.controller.ts index dabca96..fa45089 100644 --- a/src/identity-and-account/employees/controllers/employees.controller.ts +++ b/src/identity-and-account/employees/controllers/employees.controller.ts @@ -1,37 +1,35 @@ import { Controller, Get, Patch, Param, Body, NotFoundException } from "@nestjs/common"; -import { ApiBearerAuth, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger"; +import { RolesAllowed } from "src/common/decorators/roles.decorators"; +import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes"; import { EmployeeListItemDto } from "src/identity-and-account/employees/dtos/list-employee.dto"; import { EmployeeProfileItemDto } from "src/identity-and-account/employees/dtos/profil-employee.dto"; import { UpdateEmployeeDto } from "src/identity-and-account/employees/dtos/update-employee.dto"; import { EmployeesArchivalService } from "src/identity-and-account/employees/services/employees-archival.service"; import { EmployeesService } from "src/identity-and-account/employees/services/employees.service"; -@ApiBearerAuth('access-token') -// @UseGuards() +@RolesAllowed(...GLOBAL_CONTROLLER_ROLES) @Controller('employees') export class EmployeesController { constructor( private readonly employeesService: EmployeesService, - private readonly archiveService: EmployeesArchivalService, - ) {} + private readonly archiveService: EmployeesArchivalService, + ) { } @Get('employee-list') - //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ACCOUNTING) - + @RolesAllowed(...MANAGER_ROLES) findListEmployees(): Promise { return this.employeesService.findListEmployees(); } @Patch(':email') - //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) - @ApiBearerAuth('access-token') + @RolesAllowed(...MANAGER_ROLES) async updateOrArchiveOrRestore(@Param('email') email: string, @Body() dto: UpdateEmployeeDto,) { // if last_work_day is set => archive the employee // else if employee is archived and first_work_day or last_work_day = null => restore //otherwise => standard update const result = await this.archiveService.patchEmployee(email, dto); - if(!result) { - throw new NotFoundException(`Employee with email: ${ email } is not found in active or archive.`) + if (!result) { + throw new NotFoundException(`Employee with email: ${email} is not found in active or archive.`) } return result; } @@ -68,10 +66,6 @@ export class EmployeesController { // } @Get('profile/:email') - @ApiOperation({summary: 'Find employee profile' }) - @ApiParam({ name: 'email', type: String, description: 'Identifier of the employee' }) - @ApiResponse({ status: 200, description: 'Employee profile found', type: EmployeeProfileItemDto }) - @ApiResponse({ status: 400, description: 'Employee profile not found' }) findOneProfile(@Param('email') email: string): Promise { return this.employeesService.findOneProfile(email); } diff --git a/src/identity-and-account/users-management/services/abstract-user.service.ts b/src/identity-and-account/users-management/services/abstract-user.service.ts index 4e0da2e..9a2ffd1 100644 --- a/src/identity-and-account/users-management/services/abstract-user.service.ts +++ b/src/identity-and-account/users-management/services/abstract-user.service.ts @@ -4,38 +4,38 @@ import { PrismaService } from 'src/prisma/prisma.service'; @Injectable() export abstract class AbstractUserService { - constructor(protected readonly prisma: PrismaService) {} + constructor(protected readonly prisma: PrismaService) { } - findAll(): Promise { - return this.prisma.users.findMany(); - } + findAll(): Promise { + return this.prisma.users.findMany(); + } - async findOne( id: string ): Promise { - const user = await this.prisma.users.findUnique({ where: { id } }); - if (!user) { - throw new NotFoundException(`User #${id} not found`); - } - return user; - } + async findOne(id: string): Promise { + const user = await this.prisma.users.findUnique({ where: { id } }); + if (!user) { + throw new NotFoundException(`User #${id} not found`); + } + return user; + } - async findOneByEmail( email: string ): Promise> { - const user = await this.prisma.users.findUnique({ where: { email } }); - if (!user) { - throw new NotFoundException(`No user with email #${email} exists`); - } + async findOneByEmail(email: string): Promise> { + const user = await this.prisma.users.findUnique({ where: { email } }); + if (!user) { + throw new NotFoundException(`No user with email #${email} exists`); + } - const clean_user = { - first_name: user.first_name, - last_name: user.last_name, - email: user.email, - role: user.role, - } - - return clean_user; - } + const clean_user = { + first_name: user.first_name, + last_name: user.last_name, + email: user.email, + role: user.role, + } - async remove(id: string): Promise { - await this.findOne(id); - return this.prisma.users.delete({ where: { id } }); - } + return clean_user; + } + + async remove(id: string): Promise { + await this.findOne(id); + return this.prisma.users.delete({ where: { id } }); + } } diff --git a/src/time-and-attendance/time-tracker/schedule-presets/controller/schedule-presets.controller.ts b/src/time-and-attendance/time-tracker/schedule-presets/controller/schedule-presets.controller.ts index 042b8df..d96cf17 100644 --- a/src/time-and-attendance/time-tracker/schedule-presets/controller/schedule-presets.controller.ts +++ b/src/time-and-attendance/time-tracker/schedule-presets/controller/schedule-presets.controller.ts @@ -6,53 +6,54 @@ import { SchedulePresetsApplyService } from "src/time-and-attendance/time-tracke import { SchedulePresetsGetService } from "src/time-and-attendance/time-tracker/schedule-presets/services/schedule-presets-get.service"; import { SchedulePresetsUpsertService } from "src/time-and-attendance/time-tracker/schedule-presets/services/schedule-presets-upsert.service"; import { Roles as RoleEnum } from '.prisma/client'; +import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes"; @Controller('schedule-presets') +@RolesAllowed(...GLOBAL_CONTROLLER_ROLES) export class SchedulePresetsController { constructor( - private readonly upsertService: SchedulePresetsUpsertService, - private readonly getService: SchedulePresetsGetService, + private readonly upsertService: SchedulePresetsUpsertService, + private readonly getService: SchedulePresetsGetService, private readonly applyPresetsService: SchedulePresetsApplyService, - ){} + ) { } //used to create a schedule preset @Post('create') - @RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN) - async createPreset( @Req() req, @Body() dto: SchedulePresetsDto ) { + @RolesAllowed(...MANAGER_ROLES) + async createPreset(@Req() req, @Body() dto: SchedulePresetsDto) { const email = req.user?.email; return await this.upsertService.createPreset(email, dto); } //used to update an already existing schedule preset @Patch('update/:preset_id') - @RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN) - async updatePreset( @Param('preset_id', ParseIntPipe) preset_id: number,@Body() dto: SchedulePresetsUpdateDto ) { + @RolesAllowed(...MANAGER_ROLES) + async updatePreset(@Param('preset_id', ParseIntPipe) preset_id: number, @Body() dto: SchedulePresetsUpdateDto) { return await this.upsertService.updatePreset(preset_id, dto); } //used to delete a schedule preset @Delete('delete/:preset_id') @RolesAllowed(RoleEnum.ADMIN) - async deletePreset( @Param('preset_id') preset_id: number ) { + async deletePreset(@Param('preset_id') preset_id: number) { return await this.upsertService.deletePreset(preset_id); } //used to show the list of available schedule presets @Get('find-list') - @RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN) - async findListById( @Req() req) { + @RolesAllowed(...MANAGER_ROLES) + async findListById(@Req() req) { const email = req.user?.email; return this.getService.getSchedulePresets(email); } //used to apply a preset to a timesheet @Post('apply-presets') - @RolesAllowed(RoleEnum.EMPLOYEE, RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN) - async applyPresets( @Req() req, @Query('preset') preset_name: string, @Query('start') start_date: string ) { + async applyPresets(@Req() req, @Query('preset') preset_name: string, @Query('start') start_date: string) { const email = req.user?.email; - if(!preset_name?.trim()) throw new BadRequestException('Query "preset" is required'); - if(!start_date?.trim()) throw new BadRequestException('Query "start" is required YYYY-MM-DD'); + if (!preset_name?.trim()) throw new BadRequestException('Query "preset" is required'); + if (!start_date?.trim()) throw new BadRequestException('Query "start" is required YYYY-MM-DD'); return this.applyPresetsService.applyToTimesheet(email, preset_name, start_date); } } \ No newline at end of file diff --git a/src/time-and-attendance/time-tracker/shifts/controllers/shift.controller.ts b/src/time-and-attendance/time-tracker/shifts/controllers/shift.controller.ts index b9ce63d..886536b 100644 --- a/src/time-and-attendance/time-tracker/shifts/controllers/shift.controller.ts +++ b/src/time-and-attendance/time-tracker/shifts/controllers/shift.controller.ts @@ -3,17 +3,18 @@ import { ShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift import { UpdateShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-update.dto"; import { ShiftsUpsertService } from "src/time-and-attendance/time-tracker/shifts/services/shifts-upsert.service"; import { CreateShiftResult, UpdateShiftResult } from "src/time-and-attendance/utils/type.utils"; -import { Roles as RoleEnum } from '.prisma/client'; import { RolesAllowed } from "src/common/decorators/roles.decorators"; +import { GLOBAL_CONTROLLER_ROLES } from "src/common/shared/role-groupes"; + @Controller('shift') +@RolesAllowed(...GLOBAL_CONTROLLER_ROLES) export class ShiftController { constructor( private readonly upsert_service: ShiftsUpsertService, ){} @Post('create') - @RolesAllowed(RoleEnum.EMPLOYEE, RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN) createBatch( @Req() req, @Body()dtos: ShiftDto[]): Promise { const email = req.user?.email; const list = Array.isArray(dtos) ? dtos : []; @@ -21,10 +22,7 @@ export class ShiftController { return this.upsert_service.createShifts(email, dtos) } - - //change Body to receive dtos @Patch('update') - @RolesAllowed(RoleEnum.EMPLOYEE, RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN) updateBatch( @Body() dtos: UpdateShiftDto[]): Promise{ const list = Array.isArray(dtos) ? dtos: []; if(list.length === 0) throw new BadRequestException('Body is missing or invalid (update shifts)'); @@ -32,9 +30,8 @@ export class ShiftController { } @Delete(':shift_id') - @RolesAllowed(RoleEnum.EMPLOYEE, RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN) remove(@Param('shift_id') shift_id: number ) { return this.upsert_service.deleteShift(shift_id); } - + } diff --git a/src/time-and-attendance/time-tracker/shifts/services/shifts-upsert.service.ts b/src/time-and-attendance/time-tracker/shifts/services/shifts-upsert.service.ts index e1d36f4..0a2e96c 100644 --- a/src/time-and-attendance/time-tracker/shifts/services/shifts-upsert.service.ts +++ b/src/time-and-attendance/time-tracker/shifts/services/shifts-upsert.service.ts @@ -41,16 +41,16 @@ export class ShiftsUpsertService { if (normed.end_time <= normed.start_time) { const error = { error_code: 'SHIFT_OVERLAP', - conflicts: { - start_time: toStringFromHHmm(normed.start_time), - end_time: toStringFromHHmm(normed.end_time), + conflicts: { + start_time: toStringFromHHmm(normed.start_time), + end_time: toStringFromHHmm(normed.end_time), date: toStringFromDate(normed.date), }, }; return { index, error }; } - if(!normed.end_time) throw new BadRequestException('A shift needs an end_time'); - if(!normed.start_time) throw new BadRequestException('A shift needs a start_time'); + if (!normed.end_time) throw new BadRequestException('A shift needs an end_time'); + if (!normed.start_time) throw new BadRequestException('A shift needs a start_time'); const timesheet = await this.prisma.timesheets.findUnique({ where: { id: dto.timesheet_id, employee_id }, @@ -59,9 +59,9 @@ export class ShiftsUpsertService { if (!timesheet) { const error = { error_code: 'INVALID_TIMESHEET', - conflicts: { - start_time: toStringFromHHmm(normed.start_time), - end_time: toStringFromHHmm(normed.end_time), + conflicts: { + start_time: toStringFromHHmm(normed.start_time), + end_time: toStringFromHHmm(normed.end_time), date: toStringFromDate(normed.date), }, }; @@ -116,14 +116,14 @@ export class ShiftsUpsertService { if ( overlaps( { start: ordered[j - 1].start, end: ordered[j - 1].end, date: ordered[j - 1].date }, - { start: ordered[j].start, end: ordered[j].end, date: ordered[j].date }, + { start: ordered[j].start, end: ordered[j].end, date: ordered[j].date }, ) ) { const error = new ConflictException({ error_code: 'SHIFT_OVERLAP', - conflicts: { - start_time: toStringFromHHmm(ordered[j].start), - end_time: toStringFromHHmm(ordered[j].end), + conflicts: { + start_time: toStringFromHHmm(ordered[j].start), + end_time: toStringFromHHmm(ordered[j].end), date: toStringFromDate(ordered[j].date), }, }); @@ -148,7 +148,7 @@ export class ShiftsUpsertService { where: { timesheet_id, date: day_date }, select: { start_time: true, end_time: true, id: true, date: true }, }); - existing_map.set( key, rows.map((row) => ({ start_time: row.start_time, end_time: row.end_time, date: row.date }))); + existing_map.set(key, rows.map((row) => ({ start_time: row.start_time, end_time: row.end_time, date: row.date }))); } normed_shifts.forEach((x, i) => { @@ -164,8 +164,8 @@ export class ShiftsUpsertService { existing = []; existing_map.set(map_key, existing); } - const hit = existing.find(exist => overlaps({ start: exist.start_time, end: exist.end_time, date: exist.date }, - { start: normed.start_time, end: normed.end_time, date:normed.date})); + const hit = existing.find(exist => overlaps({ start: exist.start_time, end: exist.end_time, date: exist.date }, + { start: normed.start_time, end: normed.end_time, date: normed.date })); if (hit) { results[index] = { ok: false, @@ -201,7 +201,7 @@ export class ShiftsUpsertService { }; existing.push(normalized_row); existing_map.set(map_key, existing); - + const { type: bank_type } = await this.typeResolver.findTypeByBankCodeId(row.bank_code_id); const summary = await this.overtime.getWeekOvertimeSummary(timesheet_id, normed.date, tx); @@ -236,11 +236,11 @@ export class ShiftsUpsertService { // recalculate overtime after update // return an updated version to display async updateShifts(dtos: UpdateShiftDto[]): Promise { - if (!Array.isArray(dtos) || dtos.length === 0) return []; + if (!Array.isArray(dtos) || dtos.length === 0) throw new BadRequestException({ error_code: 'SHIFT_MISSING' }); const updates: UpdateShiftPayload[] = await Promise.all(dtos.map((item) => { const { id, ...rest } = item; - if (!Number.isInteger(id)) throw new ConflictException({ error_code: 'INVALID_SHIFT'}); + if (!id) throw new BadRequestException({ error_code: 'SHIFT_INVALID' }); const changes: UpdateShiftChanges = {}; if (rest.date !== undefined) changes.date = rest.date; @@ -265,13 +265,15 @@ export class ShiftsUpsertService { const existing = regroup_id.get(update.id); if (!existing) { return updates.map(exist => exist.id === update.id - ? ({ ok: false, id: update.id, error: new NotFoundException(`Shift with id: ${update.id} not found`) } as UpdateShiftResult) - : ({ ok: false, id: exist.id, error: new BadRequestException('Batch aborted due to missing shift') })); + ? ({ ok: false, id: update.id, error: new NotFoundException({ error_code: 'SHIFT_MISSING' }) } as UpdateShiftResult) + : ({ ok: false, id: exist.id, error: new BadRequestException({ error_code: 'SHIFT_INVALID' }) }) + ); } if (existing.is_approved) { return updates.map(exist => exist.id === update.id - ? ({ ok: false, id: update.id, error: new BadRequestException('Approved shift cannot be updated') } as UpdateShiftResult) - : ({ ok: false, id: exist.id, error: new BadRequestException('Batch aborted due to approved shift in update set') })); + ? ({ ok: false, id: update.id, error: new BadRequestException({ error_code: 'SHIFT_INVALID' }) } as UpdateShiftResult) + : ({ ok: false, id: exist.id, error: new BadRequestException({ error_code: 'SHIFT_INVALID' }) }) + ); } } @@ -307,12 +309,14 @@ export class ShiftsUpsertService { where: { timesheet_id: group.timesheet_id, date: day_date }, select: { id: true, start_time: true, end_time: true, date: true }, }); - groups.set(key(group.timesheet_id, day_date), { existing: existing.map(row => ({ - id: row.id, - start: row.start_time, - end: row.end_time, - date: row.date, - })), incoming: planned_updates }); + groups.set(key(group.timesheet_id, day_date), { + existing: existing.map(row => ({ + id: row.id, + start: row.start_time, + end: row.end_time, + date: row.date, + })), incoming: planned_updates + }); } for (const planned of planned_updates) { @@ -320,23 +324,23 @@ export class ShiftsUpsertService { const group = groups.get(keys)!; const conflict = group.existing.find(row => - row.id !== planned.exist_shift.id && overlaps({ start: row.start, end: row.end, date: row.date }, + row.id !== planned.exist_shift.id && overlaps({ start: row.start, end: row.end, date: row.date }, { start: planned.normed.start_time, end: planned.normed.end_time, date: planned.normed.date }) ); if (conflict) { return updates.map(exist => exist.id === planned.exist_shift.id ? ({ - ok: false, id: exist.id, error:{ + ok: false, id: exist.id, error: { error_code: 'SHIFT_OVERLAP', - conflicts: { - start_time: toStringFromHHmm(conflict.start), - end_time: toStringFromHHmm(conflict.end), + conflicts: { + start_time: toStringFromHHmm(conflict.start), + end_time: toStringFromHHmm(conflict.end), date: toStringFromDate(conflict.date), }, } } as UpdateShiftResult) - : ({ ok: false, id: exist.id, error: new BadRequestException('Batch aborted due to overlap in another update') }) + : ({ ok: false, id: exist.id, error: new BadRequestException({ error_code: 'SHIFT_OVERLAP' }) }) ); } } @@ -345,29 +349,29 @@ export class ShiftsUpsertService { for (const planned of planned_updates) { const keys = key(planned.exist_shift.timesheet_id, planned.normed.date); if (!regoup_by_day.has(keys)) regoup_by_day.set(keys, []); - regoup_by_day.get(keys)!.push({ - id: planned.exist_shift.id, - start: planned.normed.start_time, - end: planned.normed.end_time, - date: planned.normed.date + regoup_by_day.get(keys)!.push({ + id: planned.exist_shift.id, + start: planned.normed.start_time, + end: planned.normed.end_time, + date: planned.normed.date }); } - + for (const arr of regoup_by_day.values()) { arr.sort((a, b) => a.start.getTime() - b.start.getTime()); for (let i = 1; i < arr.length; i++) { if (overlaps( - { start: arr[i - 1].start, end: arr[i - 1].end, date: arr[i - 1].date }, - { start: arr[i].start, end: arr[i].end, date: arr[i].date }) + { start: arr[i - 1].start, end: arr[i - 1].end, date: arr[i - 1].date }, + { start: arr[i].start, end: arr[i].end, date: arr[i].date }) ) { - const error = { + const error = { error_code: 'SHIFT_OVERLAP', - conflicts: { - start_time: toStringFromHHmm(arr[i].start), - end_time: toStringFromHHmm(arr[i].end), + conflicts: { + start_time: toStringFromHHmm(arr[i].start), + end_time: toStringFromHHmm(arr[i].end), date: toStringFromDate(arr[i].date), }, - + }; return updates.map(exist => ({ ok: false, id: exist.id, error: error })); } @@ -426,7 +430,7 @@ export class ShiftsUpsertService { where: { id: shift_id }, select: { id: true, date: true, timesheet_id: true }, }); - if (!shift) throw new ConflictException({ error_code: 'INVALID_SHIFT'}); + if (!shift) throw new ConflictException({ error_code: 'SHIFT_INVALID' }); await tx.shifts.delete({ where: { id: shift_id } }); diff --git a/src/time-and-attendance/time-tracker/timesheets/controllers/timesheet.controller.ts b/src/time-and-attendance/time-tracker/timesheets/controllers/timesheet.controller.ts index 849a121..96bb419 100644 --- a/src/time-and-attendance/time-tracker/timesheets/controllers/timesheet.controller.ts +++ b/src/time-and-attendance/time-tracker/timesheets/controllers/timesheet.controller.ts @@ -1,31 +1,34 @@ -import { Body, Controller, Get, ParseBoolPipe, ParseIntPipe, Patch, Query, Req, UnauthorizedException} from "@nestjs/common"; +import { Body, Controller, Get, ParseBoolPipe, ParseIntPipe, Patch, Query, Req, UnauthorizedException } from "@nestjs/common"; import { RolesAllowed } from "src/common/decorators/roles.decorators"; import { GetTimesheetsOverviewService } from "src/time-and-attendance/time-tracker/timesheets/services/timesheet-get-overview.service"; -import { Roles as RoleEnum } from '.prisma/client'; import { TimesheetApprovalService } from "src/time-and-attendance/time-tracker/timesheets/services/timesheet-approval.service"; +import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes"; @Controller('timesheets') +@RolesAllowed(...GLOBAL_CONTROLLER_ROLES) export class TimesheetController { - constructor( + constructor( private readonly timesheetOverview: GetTimesheetsOverviewService, private readonly approvalService: TimesheetApprovalService, - ){} + ) { } @Get() - @RolesAllowed(RoleEnum.SUPERVISOR, RoleEnum.HR, RoleEnum.ACCOUNTING, RoleEnum.ADMIN) - async getTimesheetByIds( - @Req() req, @Query('year', ParseIntPipe) year:number, @Query('period_number', ParseIntPipe) period_number: number) { + getTimesheetByPayPeriod( + @Req() req, + @Query('year', ParseIntPipe) year: number, + @Query('period_number', ParseIntPipe) period_number: number + ) { const email = req.user?.email; - if(!email) throw new UnauthorizedException('Unauthorized User'); + if (!email) throw new UnauthorizedException('Unauthorized User'); return this.timesheetOverview.getTimesheetsForEmployeeByPeriod(email, year, period_number); } @Patch('timesheet-approval') - @RolesAllowed(RoleEnum.SUPERVISOR, RoleEnum.HR, RoleEnum.ACCOUNTING, RoleEnum.ADMIN) - async approveTimesheet( + @RolesAllowed(...MANAGER_ROLES) + approveTimesheet( @Body('timesheet_id', ParseIntPipe) timesheet_id: number, - @Body('is_approved' , ParseBoolPipe) is_approved: boolean, + @Body('is_approved', ParseBoolPipe) is_approved: boolean, ) { return this.approvalService.approveTimesheetById(timesheet_id, is_approved); }