diff --git a/src/common/decorators/roles.decorator.ts b/src/common/decorators/roles.decorator.ts new file mode 100644 index 0000000..b1efe4b --- /dev/null +++ b/src/common/decorators/roles.decorator.ts @@ -0,0 +1,3 @@ +import { SetMetadata } from "@nestjs/common"; + +export const Roles = (...roles: string[]) => SetMetadata("roles", roles); diff --git a/src/common/decorators/user.decorator.ts b/src/common/decorators/user.decorator.ts new file mode 100644 index 0000000..efbca73 --- /dev/null +++ b/src/common/decorators/user.decorator.ts @@ -0,0 +1,7 @@ +import { createParamDecorator, ExecutionContext } from "@nestjs/common"; + +export const User = createParamDecorator((data: string | undefined, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + const user = request.user; + return data ? user?.[data] : user; +}); diff --git a/src/common/dto/date_range_query.dto.ts b/src/common/dto/date_range_query.dto.ts new file mode 100644 index 0000000..973e4aa --- /dev/null +++ b/src/common/dto/date_range_query.dto.ts @@ -0,0 +1,11 @@ +import { IsDateString, IsOptional } from "class-validator"; + +export class DateRangeQueryDto { + @IsOptional() + @IsDateString() + start?: string; + + @IsOptional() + @IsDateString() + end?: string; +} diff --git a/src/common/dto/id_param.dto.ts b/src/common/dto/id_param.dto.ts new file mode 100644 index 0000000..f632953 --- /dev/null +++ b/src/common/dto/id_param.dto.ts @@ -0,0 +1,6 @@ +import { IsUUID } from "class-validator"; + +export class IdParamDto { + @IsUUID() + id: string; +} diff --git a/src/common/dto/pagination.query.ts b/src/common/dto/pagination.query.ts new file mode 100644 index 0000000..371e358 --- /dev/null +++ b/src/common/dto/pagination.query.ts @@ -0,0 +1,11 @@ +import { IsOptional, IsPositive } from "class-validator"; + +export class PaginationQueryDto { + @IsOptional() + @IsPositive() + offset?: number; + + @IsOptional() + @IsPositive() + limit?: number; +} \ No newline at end of file diff --git a/src/common/dto/search_query.dto.ts b/src/common/dto/search_query.dto.ts new file mode 100644 index 0000000..b256af1 --- /dev/null +++ b/src/common/dto/search_query.dto.ts @@ -0,0 +1,8 @@ +import { IsOptional, IsString, MinLength } from "class-validator"; + +export class SearchQueryDto { + @IsOptional() + @IsString() + @MinLength(2) + q?: string; +} diff --git a/src/common/guards/roles.guard.ts b/src/common/guards/roles.guard.ts new file mode 100644 index 0000000..6df212e --- /dev/null +++ b/src/common/guards/roles.guard.ts @@ -0,0 +1,21 @@ +import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common"; +import { Reflector } from "@nestjs/core"; +import { Observable } from "rxjs"; + +@Injectable() +export class RolesGuard implements CanActivate { + constructor(private readonly reflector: Reflector) {} + canActivate(context: ExecutionContext): boolean | Promise | Observable { + const requiredRoles = this.reflector.get('roles', context.getHandler()); + if (!requiredRoles || requiredRoles.length === 0) { + return true; // Si aucun role est requis -> accès autorise + } + + const request = context.switchToHttp().getRequest(); + const user = request.user; + if (!user || !user.role) { + return false; // Si l'utilisateur est pas authentifie ou a pas de role -> accès refusé + } + return requiredRoles.includes(user.role); + } +} \ No newline at end of file