feat(role-guards): added role-guards group and added role check to controllers
This commit is contained in:
parent
02ebb23d7a
commit
1a0532846f
|
|
@ -17,9 +17,9 @@ export class OwnershipGuard implements CanActivate {
|
|||
constructor(
|
||||
private reflector: Reflector,
|
||||
private moduleRef: ModuleRef,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean>{
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const meta = this.reflector.get<OwnershipMeta>(
|
||||
OWNER_KEY, context.getHandler(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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<Roles[]>(
|
||||
const requiredRoles = this.reflector.getAllAndOverride<Roles[]>(
|
||||
ROLES_KEY,
|
||||
ctx.getHandler(),
|
||||
[ctx.getHandler(), ctx.getClass()],
|
||||
);
|
||||
//for "deny-by-default" when role is wrong or unavailable
|
||||
if (!requiredRoles || requiredRoles.length === 0) {
|
||||
|
|
|
|||
15
src/common/shared/role-groupes.ts
Normal file
15
src/common/shared/role-groupes.ts
Normal file
|
|
@ -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,
|
||||
]
|
||||
|
|
@ -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<EmployeeListItemDto[]> {
|
||||
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<EmployeeProfileItemDto> {
|
||||
return this.employeesService.findOneProfile(email);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Users[]> {
|
||||
return this.prisma.users.findMany();
|
||||
}
|
||||
findAll(): Promise<Users[]> {
|
||||
return this.prisma.users.findMany();
|
||||
}
|
||||
|
||||
async findOne( id: string ): Promise<Users> {
|
||||
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<Users> {
|
||||
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<Partial<Users>> {
|
||||
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<Partial<Users>> {
|
||||
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,
|
||||
}
|
||||
const clean_user = {
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
}
|
||||
|
||||
return clean_user;
|
||||
}
|
||||
return clean_user;
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<Users> {
|
||||
await this.findOne(id);
|
||||
return this.prisma.users.delete({ where: { id } });
|
||||
}
|
||||
async remove(id: string): Promise<Users> {
|
||||
await this.findOne(id);
|
||||
return this.prisma.users.delete({ where: { id } });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<CreateShiftResult[]> {
|
||||
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<UpdateShiftResult[]>{
|
||||
const list = Array.isArray(dtos) ? dtos: [];
|
||||
if(list.length === 0) throw new BadRequestException('Body is missing or invalid (update shifts)');
|
||||
|
|
@ -32,7 +30,6 @@ 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ export class ShiftsUpsertService {
|
|||
};
|
||||
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 },
|
||||
|
|
@ -116,7 +116,7 @@ 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({
|
||||
|
|
@ -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) => {
|
||||
|
|
@ -165,7 +165,7 @@ export class ShiftsUpsertService {
|
|||
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}));
|
||||
{ start: normed.start_time, end: normed.end_time, date: normed.date }));
|
||||
if (hit) {
|
||||
results[index] = {
|
||||
ok: false,
|
||||
|
|
@ -236,11 +236,11 @@ export class ShiftsUpsertService {
|
|||
// recalculate overtime after update
|
||||
// return an updated version to display
|
||||
async updateShifts(dtos: UpdateShiftDto[]): Promise<UpdateShiftResult[]> {
|
||||
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) {
|
||||
|
|
@ -327,7 +331,7 @@ export class ShiftsUpsertService {
|
|||
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),
|
||||
|
|
@ -336,7 +340,7 @@ export class ShiftsUpsertService {
|
|||
},
|
||||
}
|
||||
} 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' }) })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -358,7 +362,7 @@ export class ShiftsUpsertService {
|
|||
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].start, end: arr[i].end, date: arr[i].date })
|
||||
) {
|
||||
const error = {
|
||||
error_code: 'SHIFT_OVERLAP',
|
||||
|
|
@ -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 } });
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user