refactor(controllers): added ModuleAccessAllowed and Access decorators
This commit is contained in:
parent
0f509a920f
commit
ebc1cd77d8
|
|
@ -463,6 +463,20 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/employees/personal-profile": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "EmployeesController_findOwnProfile",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Employees"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/employees/profile": {
|
"/employees/profile": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "EmployeesController_findProfile",
|
"operationId": "EmployeesController_findProfile",
|
||||||
|
|
|
||||||
|
|
@ -381,6 +381,17 @@ enum Roles {
|
||||||
@@map("roles")
|
@@map("roles")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Modules {
|
||||||
|
timesheets
|
||||||
|
timesheets_approval
|
||||||
|
employee_list
|
||||||
|
employee_management
|
||||||
|
personal_profile
|
||||||
|
dashboard
|
||||||
|
|
||||||
|
@@map("modules")
|
||||||
|
}
|
||||||
|
|
||||||
enum LeaveTypes {
|
enum LeaveTypes {
|
||||||
SICK // maladie ou repos
|
SICK // maladie ou repos
|
||||||
VACATION // paye
|
VACATION // paye
|
||||||
|
|
|
||||||
8
src/common/decorators/modules-guard.decorators.ts
Normal file
8
src/common/decorators/modules-guard.decorators.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { SetMetadata } from '@nestjs/common';
|
||||||
|
import { Modules } from 'src/common/mappers/module-access.mapper';
|
||||||
|
|
||||||
|
export const MODULES_KEY = 'modules';
|
||||||
|
export const ModuleAccessAllowed = (...modules: Modules[]) =>
|
||||||
|
SetMetadata(MODULES_KEY, modules);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { SetMetadata } from '@nestjs/common';
|
|
||||||
import { Roles } from '@prisma/client';
|
|
||||||
|
|
||||||
export const ROLES_KEY = 'roles';
|
|
||||||
export const RolesAllowed = (...roles: Roles[]) =>
|
|
||||||
SetMetadata(ROLES_KEY, roles);
|
|
||||||
|
|
||||||
|
|
||||||
43
src/common/guards/modules.guard.ts
Normal file
43
src/common/guards/modules.guard.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ExecutionContext,
|
||||||
|
ForbiddenException,
|
||||||
|
Injectable,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { MODULES_KEY } from '../decorators/modules-guard.decorators';
|
||||||
|
import { Modules, Roles } from '.prisma/client';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface RequestWithUser extends Request {
|
||||||
|
// TODO: Create an actual user model based on OAuth signin
|
||||||
|
user: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ModulesGuard implements CanActivate {
|
||||||
|
constructor(private reflector: Reflector) { }
|
||||||
|
canActivate(ctx: ExecutionContext): boolean {
|
||||||
|
const requiredModules = this.reflector.getAllAndOverride<Modules[]>(
|
||||||
|
MODULES_KEY,
|
||||||
|
[ctx.getHandler(), ctx.getClass()],
|
||||||
|
);
|
||||||
|
//for "deny-by-default" when role is wrong or unavailable
|
||||||
|
if (!requiredModules || requiredModules.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const request = ctx.switchToHttp().getRequest<RequestWithUser>();
|
||||||
|
const user = request.user;
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!requiredModules.includes(user.role)) {
|
||||||
|
throw new ForbiddenException(
|
||||||
|
`The role ${user.role} is not authorized to access this resource.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
import {
|
|
||||||
CanActivate,
|
|
||||||
ExecutionContext,
|
|
||||||
ForbiddenException,
|
|
||||||
Injectable,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { Reflector } from '@nestjs/core';
|
|
||||||
import { ROLES_KEY } from '../decorators/roles.decorators';
|
|
||||||
import { Roles } from '.prisma/client';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface RequestWithUser extends Request {
|
|
||||||
// TODO: Create an actual user model based on OAuth signin
|
|
||||||
user: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RolesGuard implements CanActivate {
|
|
||||||
constructor(private reflector: Reflector) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* @function canActivate
|
|
||||||
* @description
|
|
||||||
* Authorization guard that checks whether the current user has one of the required roles
|
|
||||||
* to access a specific route handler. It uses metadata defined by the `@Roles()` decorator
|
|
||||||
* and verifies the user's role accordingly.
|
|
||||||
*
|
|
||||||
* If no roles are specified for the route, access is granted by default.
|
|
||||||
* If the user is not authenticated or does not have a required role, access is denied.
|
|
||||||
*
|
|
||||||
* @param {ExecutionContext} ctx - The current execution context, which provides access
|
|
||||||
* to route metadata and the HTTP request.
|
|
||||||
*
|
|
||||||
* @returns {boolean} - Returns `true` if access is allowed, otherwise throws a `ForbiddenException`
|
|
||||||
* or returns `false` if the user is not authenticated.
|
|
||||||
*/
|
|
||||||
canActivate(ctx: ExecutionContext): boolean {
|
|
||||||
const requiredRoles = this.reflector.getAllAndOverride<Roles[]>(
|
|
||||||
ROLES_KEY,
|
|
||||||
[ctx.getHandler(), ctx.getClass()],
|
|
||||||
);
|
|
||||||
//for "deny-by-default" when role is wrong or unavailable
|
|
||||||
if (!requiredRoles || requiredRoles.length === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const request = ctx.switchToHttp().getRequest<RequestWithUser>();
|
|
||||||
const user = request.user;
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!requiredRoles.includes(user.role)) {
|
|
||||||
throw new ForbiddenException(
|
|
||||||
`The role ${user.role} is not authorized to access this resource.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,46 +4,37 @@ import { Result } from "src/common/errors/result-error.factory";
|
||||||
import { EmployeeDetailedDto } from "src/identity-and-account/employees/dtos/employee-detailed.dto";
|
import { EmployeeDetailedDto } from "src/identity-and-account/employees/dtos/employee-detailed.dto";
|
||||||
import { EmployeeDto } from "src/identity-and-account/employees/dtos/employee.dto";
|
import { EmployeeDto } from "src/identity-and-account/employees/dtos/employee.dto";
|
||||||
import { EmployeesService } from "src/identity-and-account/employees/services/employees.service";
|
import { EmployeesService } from "src/identity-and-account/employees/services/employees.service";
|
||||||
import { AccessGetService } from "src/identity-and-account/user-module-access/services/module-access-get.service";
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
|
||||||
//TODO: create a custom decorator to replace the findModuleAcces call function
|
//TODO: create a custom decorator to replace the findModuleAcces call function
|
||||||
|
|
||||||
@Controller('employees')
|
@Controller('employees')
|
||||||
export class EmployeesController {
|
export class EmployeesController {
|
||||||
constructor(
|
constructor(private readonly employeesService: EmployeesService) { }
|
||||||
private readonly employeesService: EmployeesService,
|
|
||||||
private readonly accessGetService: AccessGetService,
|
@Get('personal-profile')
|
||||||
) { }
|
@ModuleAccessAllowed(ModulesEnum.personal_profile)
|
||||||
|
async findOwnProfile(@Access('email') email: string): Promise<Result<Partial<EmployeeDetailedDto>, string>> {
|
||||||
|
return await this.employeesService.findOwnProfile(email);
|
||||||
|
}
|
||||||
|
|
||||||
@Get('profile')
|
@Get('profile')
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
async findProfile(@Access('email') email: string, @Query('employee_email') employee_email?: string,
|
async findProfile(@Access('email') email: string, @Query('employee_email') employee_email?: string,
|
||||||
): Promise<Result<Partial<EmployeeDetailedDto>, string>> {
|
): Promise<Result<Partial<EmployeeDetailedDto>, string>> {
|
||||||
const granted_access = await this.accessGetService.findModuleAccess(email);
|
return await this.employeesService.findOneDetailedProfile(email, employee_email);
|
||||||
if (!granted_access.success) return { success: false, error: 'INVALID_USER' };
|
|
||||||
if (!granted_access.data.employee_management) {
|
|
||||||
return await this.employeesService.findOwnProfile(email);
|
|
||||||
} else if (granted_access.data.employee_management) {
|
|
||||||
return await this.employeesService.findOneDetailedProfile(email,employee_email);
|
|
||||||
} else {
|
|
||||||
return { success: false, error: 'INVALID_USER' }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('employee-list')
|
@Get('employee-list')
|
||||||
async findListEmployees(@Access('email') email: string
|
@ModuleAccessAllowed(ModulesEnum.employee_list)
|
||||||
): Promise<Result<EmployeeDto[], string>> {
|
async findListEmployees(): Promise<Result<EmployeeDto[], string>> {
|
||||||
const granted_access = await this.accessGetService.findModuleAccess(email);
|
|
||||||
if (!granted_access.success) return { success: false, error: 'INVALID_USER' };
|
|
||||||
if (!granted_access.data.employee_management) return { success: false, error: 'UNAUTHORIZED_ACCESS' };
|
|
||||||
return this.employeesService.findListEmployees();
|
return this.employeesService.findListEmployees();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
async createEmployee(@Access('email') email: string, @Body() dto: EmployeeDetailedDto
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
): Promise<Result<boolean, string>> {
|
async createEmployee(@Body() dto: EmployeeDetailedDto): Promise<Result<boolean, string>> {
|
||||||
const granted_access = await this.accessGetService.findModuleAccess(email);
|
|
||||||
if (!granted_access.success) return { success: false, error: 'INVALID_USER' };
|
|
||||||
if (!granted_access.data.employee_management) return { success: false, error: 'UNAUTHORIZED_ACCESS' };
|
|
||||||
return await this.employeesService.createEmployee(dto);
|
return await this.employeesService.createEmployee(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
11
src/main.ts
11
src/main.ts
|
|
@ -1,18 +1,15 @@
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
//import and if case for @nestjs/schedule Cron jobs
|
|
||||||
import * as nodeCrypto from 'crypto';
|
import * as nodeCrypto from 'crypto';
|
||||||
if (!(globalThis as any).crypto) {
|
if (!(globalThis as any).crypto) {
|
||||||
(globalThis as any).crypto = nodeCrypto;
|
(globalThis as any).crypto = nodeCrypto;
|
||||||
}
|
}
|
||||||
import { ensureAttachmentsTmpDir } from './config/attachment.fs';
|
import { ensureAttachmentsTmpDir } from './config/attachment.fs';
|
||||||
|
|
||||||
import { resolveAttachmentsRoot } from './config/attachment.config';// log to be removed post dev
|
import { resolveAttachmentsRoot } from './config/attachment.config';// log to be removed post dev
|
||||||
import { ATT_TMP_DIR } from './config/attachment.config'; // log to be removed post dev
|
import { ATT_TMP_DIR } from './config/attachment.config'; // log to be removed post dev
|
||||||
|
import { NestFactory, Reflector } from '@nestjs/core';
|
||||||
import { ModuleRef, NestFactory, Reflector } from '@nestjs/core';
|
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
// import { JwtAuthGuard } from './modules/authentication/guards/jwt-auth.guard';
|
// import { JwtAuthGuard } from './modules/authentication/guards/jwt-auth.guard';
|
||||||
import { RolesGuard } from './common/guards/roles.guard';
|
import { ModulesGuard } from './common/guards/modules.guard';
|
||||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
import * as session from 'express-session';
|
import * as session from 'express-session';
|
||||||
|
|
@ -26,11 +23,11 @@ const SESSION_TOKEN_DURATION_MINUTES = 180
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
|
|
||||||
const reflector = app.get(Reflector); //setup Reflector for Roles()
|
const reflector = app.get(Reflector);
|
||||||
|
|
||||||
app.useGlobalGuards(
|
app.useGlobalGuards(
|
||||||
// new JwtAuthGuard(reflector), //Authentification JWT
|
// new JwtAuthGuard(reflector), //Authentification JWT
|
||||||
new RolesGuard(reflector), //deny-by-default and Role-based Access Control
|
new ModulesGuard(reflector), //deny-by-default and Module-based Access Control
|
||||||
);
|
);
|
||||||
|
|
||||||
// Authentication and session
|
// Authentication and session
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from "@nestjs/common";
|
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from "@nestjs/common";
|
||||||
import { BankCodesService } from "../services/bank-codes.service";
|
import { BankCodesService } from "../services/bank-codes.service";
|
||||||
import { BankCodeDto } from "../dtos/bank-code.dto";
|
import { BankCodeDto } from "../dtos/bank-code.dto";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
import { PAY_SERVICE } from "src/common/shared/role-groupes";
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
|
||||||
@Controller('bank-codes')
|
@Controller('bank-codes')
|
||||||
@RolesAllowed(...PAY_SERVICE)
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
export class BankCodesControllers {
|
export class BankCodesControllers {
|
||||||
constructor(private readonly bankCodesService: BankCodesService) {}
|
constructor(private readonly bankCodesService: BankCodesService) {}
|
||||||
//_____________________________________________________________________________________________
|
//_____________________________________________________________________________________________
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
import { Controller, Get, Header, Query} from "@nestjs/common";
|
import { Controller, Get, Header, Query} from "@nestjs/common";
|
||||||
import { CsvExportService } from "../services/csv-exports.service";
|
import { CsvExportService } from "../services/csv-exports.service";
|
||||||
import { ExportCsvOptionsDto } from "../dtos/export-csv-options.dto";
|
import { ExportCsvOptionsDto } from "../dtos/export-csv-options.dto";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
import { PAY_SERVICE } from "src/common/shared/role-groupes";
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
|
||||||
|
|
||||||
@Controller('exports')
|
@Controller('exports')
|
||||||
@RolesAllowed(...PAY_SERVICE)
|
|
||||||
export class CsvExportController {
|
export class CsvExportController {
|
||||||
constructor(private readonly csvService: CsvExportService) {}
|
constructor(private readonly csvService: CsvExportService) {}
|
||||||
|
|
||||||
@Get('csv')
|
@Get('csv')
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
@Header('Content-Type', 'text/csv; charset=utf-8')
|
@Header('Content-Type', 'text/csv; charset=utf-8')
|
||||||
@Header('Content-Disposition', 'attachment; filename="export.csv"')
|
@Header('Content-Disposition', 'attachment; filename="export.csv"')
|
||||||
async exportCsv(@Query() query: ExportCsvOptionsDto ): Promise<Buffer> {
|
async exportCsv(@Query() query: ExportCsvOptionsDto ): Promise<Buffer> {
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,30 @@
|
||||||
import { Controller, Post, Param, Body, Patch, Delete, Req, UnauthorizedException } from "@nestjs/common";
|
import { Controller, Post, Param, Body, Patch, Delete, Req, UnauthorizedException } from "@nestjs/common";
|
||||||
import { ExpenseUpsertService } from "src/time-and-attendance/expenses/services/expense-upsert.service";
|
import { ExpenseUpsertService } from "src/time-and-attendance/expenses/services/expense-upsert.service";
|
||||||
import { ExpenseDto } from "src/time-and-attendance/expenses/dtos/expense-create.dto";
|
import { ExpenseDto } from "src/time-and-attendance/expenses/dtos/expense-create.dto";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
import { Result } from "src/common/errors/result-error.factory";
|
||||||
import { GLOBAL_CONTROLLER_ROLES } from "src/common/shared/role-groupes";
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
import { Result } from "src/common/errors/result-error.factory";
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
import { Access } from "src/common/decorators/module-access.decorators";
|
||||||
|
|
||||||
@Controller('expense')
|
@Controller('expense')
|
||||||
@RolesAllowed(...GLOBAL_CONTROLLER_ROLES)
|
|
||||||
export class ExpenseController {
|
export class ExpenseController {
|
||||||
constructor(private readonly upsert_service: ExpenseUpsertService) { }
|
constructor(private readonly upsert_service: ExpenseUpsertService) { }
|
||||||
|
|
||||||
@Post('create')
|
@Post('create')
|
||||||
create(@Req() req, @Body() dto: ExpenseDto): Promise<Result<ExpenseDto, string>> {
|
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||||
const email = req.user?.email;
|
create(@Access('email') email: string, @Body() dto: ExpenseDto): Promise<Result<ExpenseDto, string>> {
|
||||||
if (!email) throw new UnauthorizedException('Unauthorized User');
|
if (!email) throw new UnauthorizedException('Unauthorized User');
|
||||||
return this.upsert_service.createExpense(dto, email);
|
return this.upsert_service.createExpense(dto, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch('update')
|
@Patch('update')
|
||||||
update(@Body() dto: ExpenseDto, @Req() req): Promise<Result<ExpenseDto, string>> {
|
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||||
const email = req.user?.email;
|
update(@Body() dto: ExpenseDto, @Access('email') email: string): Promise<Result<ExpenseDto, string>> {
|
||||||
return this.upsert_service.updateExpense(dto, email);
|
return this.upsert_service.updateExpense(dto, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete('delete/:expense_id')
|
@Delete('delete/:expense_id')
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||||
remove(@Param('expense_id') expense_id: number): Promise<Result<number, string>> {
|
remove(@Param('expense_id') expense_id: number): Promise<Result<number, string>> {
|
||||||
return this.upsert_service.deleteExpense(expense_id);
|
return this.upsert_service.deleteExpense(expense_id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import { Body, Controller, Get, Param, ParseBoolPipe, ParseIntPipe, Patch, Query, Req, UnauthorizedException } from "@nestjs/common";
|
import { Body, Controller, Get, Param, ParseBoolPipe, ParseIntPipe, Patch, Query, UnauthorizedException } from "@nestjs/common";
|
||||||
import { PayPeriodOverviewDto } from "../dtos/overview-pay-period.dto";
|
import { PayPeriodOverviewDto } from "../dtos/overview-pay-period.dto";
|
||||||
import { PayPeriodsQueryService } from "../services/pay-periods-query.service";
|
import { PayPeriodsQueryService } from "../services/pay-periods-query.service";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
|
||||||
import { PayPeriodsCommandService } from "../services/pay-periods-command.service";
|
import { PayPeriodsCommandService } from "../services/pay-periods-command.service";
|
||||||
import { PayPeriodBundleDto } from "../dtos/bundle-pay-period.dto";
|
import { PayPeriodBundleDto } from "../dtos/bundle-pay-period.dto";
|
||||||
import { BulkCrewApprovalDto } from "../dtos/bulk-crew-approval.dto";
|
import { BulkCrewApprovalDto } from "../dtos/bulk-crew-approval.dto";
|
||||||
import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes";
|
|
||||||
import { Result } from "src/common/errors/result-error.factory";
|
import { Result } from "src/common/errors/result-error.factory";
|
||||||
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
import { Access } from "src/common/decorators/module-access.decorators";
|
||||||
|
|
||||||
@Controller('pay-periods')
|
@Controller('pay-periods')
|
||||||
@RolesAllowed(...GLOBAL_CONTROLLER_ROLES)
|
|
||||||
export class PayPeriodsController {
|
export class PayPeriodsController {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -18,6 +18,7 @@ export class PayPeriodsController {
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@Get('current-and-all')
|
@Get('current-and-all')
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
async getCurrentAndAll(@Query('date') date?: string): Promise<Result<PayPeriodBundleDto, string>> {
|
async getCurrentAndAll(@Query('date') date?: string): Promise<Result<PayPeriodBundleDto, string>> {
|
||||||
const current = await this.queryService.findCurrent(date);
|
const current = await this.queryService.findCurrent(date);
|
||||||
if (!current.success) return { success: false, error: 'INVALID_PAY_PERIOD' };
|
if (!current.success) return { success: false, error: 'INVALID_PAY_PERIOD' };
|
||||||
|
|
@ -29,11 +30,13 @@ export class PayPeriodsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get("date/:date")
|
@Get("date/:date")
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
async findByDate(@Param("date") date: string) {
|
async findByDate(@Param("date") date: string) {
|
||||||
return this.queryService.findByDate(date);
|
return this.queryService.findByDate(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(":year/:periodNumber")
|
@Get(":year/:periodNumber")
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
async findOneByYear(
|
async findOneByYear(
|
||||||
@Param("year", ParseIntPipe) year: number,
|
@Param("year", ParseIntPipe) year: number,
|
||||||
@Param("periodNumber", ParseIntPipe) period_no: number,
|
@Param("periodNumber", ParseIntPipe) period_no: number,
|
||||||
|
|
@ -42,26 +45,25 @@ export class PayPeriodsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch("crew/pay-period-approval")
|
@Patch("crew/pay-period-approval")
|
||||||
@RolesAllowed(...MANAGER_ROLES)
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
async bulkApproval(@Req() req, @Body() dto: BulkCrewApprovalDto) {
|
async bulkApproval(@Access('email') email:string, @Body() dto: BulkCrewApprovalDto) {
|
||||||
const email = req.user?.email;
|
|
||||||
if (!email) throw new UnauthorizedException(`Session infos not found`);
|
if (!email) throw new UnauthorizedException(`Session infos not found`);
|
||||||
return this.commandService.bulkApproveCrew(email, dto);
|
return this.commandService.bulkApproveCrew(email, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('crew/:year/:periodNumber')
|
@Get('crew/:year/:periodNumber')
|
||||||
@RolesAllowed(...MANAGER_ROLES)
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
async getCrewOverview(@Req() req,
|
async getCrewOverview(@Access('email') email:string,
|
||||||
@Param('year', ParseIntPipe) year: number,
|
@Param('year', ParseIntPipe) year: number,
|
||||||
@Param('periodNumber', ParseIntPipe) period_no: number,
|
@Param('periodNumber', ParseIntPipe) period_no: number,
|
||||||
@Query('includeSubtree', new ParseBoolPipe({ optional: true })) include_subtree = false,
|
@Query('includeSubtree', new ParseBoolPipe({ optional: true })) include_subtree = false,
|
||||||
): Promise<Result<PayPeriodOverviewDto, string>> {
|
): Promise<Result<PayPeriodOverviewDto, string>> {
|
||||||
const email = req.user?.email;
|
|
||||||
if (!email) throw new UnauthorizedException(`Session infos not found`);
|
if (!email) throw new UnauthorizedException(`Session infos not found`);
|
||||||
return this.queryService.getCrewOverview(year, period_no, email, include_subtree);
|
return this.queryService.getCrewOverview(year, period_no, email, include_subtree);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('overview/:year/:periodNumber')
|
@Get('overview/:year/:periodNumber')
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
async getOverviewByYear(
|
async getOverviewByYear(
|
||||||
@Param('year', ParseIntPipe) year: number,
|
@Param('year', ParseIntPipe) year: number,
|
||||||
@Param('periodNumber', ParseIntPipe) period_no: number,
|
@Param('periodNumber', ParseIntPipe) period_no: number,
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import { Controller, Param, Query, Body, Get, Post, ParseIntPipe, Delete, Patch, Req } from "@nestjs/common";
|
import { Controller, Param, Body, Get, Post, ParseIntPipe, Delete, Patch } from "@nestjs/common";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
|
||||||
import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes";
|
|
||||||
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto";
|
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto";
|
||||||
import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service";
|
import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service";
|
||||||
import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-get.service";
|
import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-get.service";
|
||||||
import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-create.service";
|
import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-create.service";
|
||||||
import { SchedulePresetUpdateDeleteService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update-delete.service";
|
import { SchedulePresetUpdateDeleteService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update-delete.service";
|
||||||
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
import { Access } from "src/common/decorators/module-access.decorators";
|
||||||
|
|
||||||
@Controller('schedule-presets')
|
@Controller('schedule-presets')
|
||||||
@RolesAllowed(...GLOBAL_CONTROLLER_ROLES)
|
|
||||||
export class SchedulePresetsController {
|
export class SchedulePresetsController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly createService: SchedulePresetsCreateService,
|
private readonly createService: SchedulePresetsCreateService,
|
||||||
|
|
@ -19,48 +19,39 @@ export class SchedulePresetsController {
|
||||||
|
|
||||||
// used to create a schedule preset
|
// used to create a schedule preset
|
||||||
@Post('create')
|
@Post('create')
|
||||||
@RolesAllowed(...MANAGER_ROLES)
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
async createPreset(@Req() req, @Body() dto: SchedulePresetsDto) {
|
async createPreset(@Access('email') email: string, @Body() dto: SchedulePresetsDto) {
|
||||||
const email = req.user?.email;
|
|
||||||
return await this.createService.createPreset(email, dto);
|
return await this.createService.createPreset(email, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
//used to update an already existing schedule preset
|
//used to update an already existing schedule preset
|
||||||
@Patch('update/:preset_id')
|
@Patch('update/:preset_id')
|
||||||
@RolesAllowed(...MANAGER_ROLES)
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
async updatePreset(
|
async updatePreset(
|
||||||
@Param('preset_id', ParseIntPipe) preset_id: number,
|
@Param('preset_id', ParseIntPipe) preset_id: number, @Body() dto: SchedulePresetsDto, @Access('email') email: string) {
|
||||||
@Body() dto: SchedulePresetsDto,
|
|
||||||
@Req() req,
|
|
||||||
) {
|
|
||||||
const email = req.user?.email;
|
|
||||||
return await this.updateDeleteService.updatePreset(preset_id, dto, email);
|
return await this.updateDeleteService.updatePreset(preset_id, dto, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
//used to delete a schedule preset
|
//used to delete a schedule preset
|
||||||
@Delete('delete/:preset_id')
|
@Delete('delete/:preset_id')
|
||||||
@RolesAllowed(...MANAGER_ROLES)
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
async deletePreset(@Param('preset_id', ParseIntPipe) preset_id: number, @Req() req) {
|
async deletePreset(
|
||||||
const email = req.user?.email;
|
@Param('preset_id', ParseIntPipe) preset_id: number, @Access('email') email: string) {
|
||||||
return await this.updateDeleteService.deletePreset(preset_id, email);
|
return await this.updateDeleteService.deletePreset(preset_id, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
//used to show the list of available schedule presets
|
//used to show the list of available schedule presets
|
||||||
@Get('find-list')
|
@Get('find-list')
|
||||||
@RolesAllowed(...MANAGER_ROLES)
|
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||||
async findListById(@Req() req) {
|
async findListById(@Access('email') email: string) {
|
||||||
const email = req.user?.email;
|
|
||||||
return this.getService.getSchedulePresets(email);
|
return this.getService.getSchedulePresets(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
//used to apply a preset to a timesheet
|
//used to apply a preset to a timesheet
|
||||||
@Post('apply-presets')
|
@Post('apply-presets')
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||||
async applyPresets(
|
async applyPresets(
|
||||||
@Body('preset') preset_id: number,
|
@Body('preset') preset_id: number, @Body('start') start_date: string, @Access('email') email: string) {
|
||||||
@Body('start') start_date: string,
|
|
||||||
@Req() req
|
|
||||||
) {
|
|
||||||
const email = req.user?.email;
|
|
||||||
return this.applyPresetsService.applyToTimesheet(email, preset_id, start_date);
|
return this.applyPresetsService.applyToTimesheet(email, preset_id, start_date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
import { Body, Controller, Delete, Param, Patch, Post, Req } from "@nestjs/common";
|
import { Body, Controller, Delete, Param, Patch, Post } from "@nestjs/common";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
|
||||||
import { GLOBAL_CONTROLLER_ROLES } from "src/common/shared/role-groupes";
|
|
||||||
import { Result } from "src/common/errors/result-error.factory";
|
import { Result } from "src/common/errors/result-error.factory";
|
||||||
import { ShiftDto } from "src/time-and-attendance/shifts/dtos/shift-create.dto";
|
import { ShiftDto } from "src/time-and-attendance/shifts/dtos/shift-create.dto";
|
||||||
import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service";
|
import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service";
|
||||||
import { ShiftsUpdateDeleteService } from "src/time-and-attendance/shifts/services/shifts-update-delete.service";
|
import { ShiftsUpdateDeleteService } from "src/time-and-attendance/shifts/services/shifts-update-delete.service";
|
||||||
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
import { Access } from "src/common/decorators/module-access.decorators";
|
||||||
|
|
||||||
@Controller('shift')
|
@Controller('shift')
|
||||||
@RolesAllowed(...GLOBAL_CONTROLLER_ROLES)
|
|
||||||
export class ShiftController {
|
export class ShiftController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly create_service: ShiftsCreateService,
|
private readonly create_service: ShiftsCreateService,
|
||||||
private readonly update_delete_service: ShiftsUpdateDeleteService,
|
private readonly update_delete_service: ShiftsUpdateDeleteService,
|
||||||
){}
|
) { }
|
||||||
|
|
||||||
@Post('create')
|
@Post('create')
|
||||||
createBatch( @Req() req, @Body()dtos: ShiftDto[]): Promise<Result<ShiftDto[], string>> {
|
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||||
const email = req.user?.email;
|
createBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<ShiftDto[], string>> {
|
||||||
return this.create_service.createOneOrManyShifts(email, dtos)
|
return this.create_service.createOneOrManyShifts(email, dtos)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch('update')
|
@Patch('update')
|
||||||
updateBatch( @Body() dtos: ShiftDto[], @Req() req): Promise<Result<ShiftDto[], string>>{
|
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||||
const email = req.user?.email;
|
updateBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<ShiftDto[], string>> {
|
||||||
return this.update_delete_service.updateOneOrManyShifts(dtos, email);
|
return this.update_delete_service.updateOneOrManyShifts(dtos, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':shift_id')
|
@Delete(':shift_id')
|
||||||
remove(@Param('shift_id') shift_id: number ): Promise<Result<number, string>> {
|
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||||
|
remove(@Param('shift_id') shift_id: number): Promise<Result<number, string>> {
|
||||||
return this.update_delete_service.deleteShift(shift_id);
|
return this.update_delete_service.deleteShift(shift_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { Body, Controller, Get, Param, ParseBoolPipe, ParseIntPipe, Patch, Query, Req, UnauthorizedException } from "@nestjs/common";
|
import { Body, Controller, Get, Param, ParseBoolPipe, ParseIntPipe, Patch, Query, Req, UnauthorizedException } from "@nestjs/common";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
|
||||||
import { GetTimesheetsOverviewService } from "src/time-and-attendance/timesheets/services/timesheet-get-overview.service";
|
import { GetTimesheetsOverviewService } from "src/time-and-attendance/timesheets/services/timesheet-get-overview.service";
|
||||||
import { TimesheetApprovalService } from "src/time-and-attendance/timesheets/services/timesheet-approval.service";
|
import { TimesheetApprovalService } from "src/time-and-attendance/timesheets/services/timesheet-approval.service";
|
||||||
import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes";
|
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
|
import { Modules as ModulesEnum } from ".prisma/client";
|
||||||
|
import { Access } from "src/common/decorators/module-access.decorators";
|
||||||
|
|
||||||
|
|
||||||
@Controller('timesheets')
|
@Controller('timesheets')
|
||||||
@RolesAllowed(...GLOBAL_CONTROLLER_ROLES)
|
|
||||||
export class TimesheetController {
|
export class TimesheetController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly timesheetOverview: GetTimesheetsOverviewService,
|
private readonly timesheetOverview: GetTimesheetsOverviewService,
|
||||||
|
|
@ -14,19 +14,18 @@ export class TimesheetController {
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@Get(':year/:period_number')
|
@Get(':year/:period_number')
|
||||||
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
getTimesheetByPayPeriod(
|
getTimesheetByPayPeriod(
|
||||||
@Req() req,
|
@Access('email') email: string,
|
||||||
@Param('year', ParseIntPipe) year: number,
|
@Param('year', ParseIntPipe) year: number,
|
||||||
@Param('period_number', ParseIntPipe) period_number: number,
|
@Param('period_number', ParseIntPipe) period_number: number,
|
||||||
@Query('employee_email') employee_email?: string,
|
@Query('employee_email') employee_email?: string,
|
||||||
) {
|
) {
|
||||||
const email = req.user?.email;
|
|
||||||
if (!email) throw new UnauthorizedException('Unauthorized User');
|
|
||||||
return this.timesheetOverview.getTimesheetsForEmployeeByPeriod(email, year, period_number, employee_email);
|
return this.timesheetOverview.getTimesheetsForEmployeeByPeriod(email, year, period_number, employee_email);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch('timesheet-approval')
|
@Patch('timesheet-approval')
|
||||||
@RolesAllowed(...MANAGER_ROLES)
|
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||||
approveTimesheet(
|
approveTimesheet(
|
||||||
@Body('timesheet_id', ParseIntPipe) timesheet_id: number,
|
@Body('timesheet_id', ParseIntPipe) timesheet_id: number,
|
||||||
@Body('is_approved', ParseBoolPipe) is_approved: boolean,
|
@Body('is_approved', ParseBoolPipe) is_approved: boolean,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user