fix(api/validation): restore strict forbidNonWhitelisted: true and decorate all GET route queries with explicit DTOs across admin and application APIs
Some checks failed
Deploy Canina / deploy (push) Failing after 28s

This commit is contained in:
parsa aghaei 2026-08-08 18:45:57 +03:30
parent 7cc9194827
commit fa688e2f8b
10 changed files with 53 additions and 13 deletions

View File

@ -15,6 +15,7 @@ import {
ProductInput,
CouponInput,
} from './admin.service';
import { AdminQueryDto } from './dto/admin-query.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import {
ApiTags,
@ -42,7 +43,7 @@ export class AdminController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getUsers(@Query() query: PaginationQuery) {
async getUsers(@Query() query: AdminQueryDto) {
const result = await this.adminService.getUsers(query);
return { success: true, ...result };
}
@ -87,7 +88,7 @@ export class AdminController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getProducts(@Query() query: PaginationQuery) {
async getProducts(@Query() query: AdminQueryDto) {
const result = await this.adminService.getProducts(query);
return { success: true, ...result };
}
@ -121,7 +122,7 @@ export class AdminController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'status', required: false, description: 'فیلتر وضعیت' })
async getOrders(@Query() query: PaginationQuery) {
async getOrders(@Query() query: AdminQueryDto) {
const result = await this.adminService.getOrders(query);
return { success: true, ...result };
}
@ -146,7 +147,7 @@ export class AdminController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getCoupons(@Query() query: PaginationQuery) {
async getCoupons(@Query() query: AdminQueryDto) {
const coupons = await this.adminService.getCoupons(query);
return { success: true, ...coupons };
}
@ -184,7 +185,7 @@ export class AdminController {
@Get('doctors')
@ApiOperation({ summary: 'لیست پزشکان و متخصصین' })
async getDoctors() {
async getDoctors(@Query() query: AdminQueryDto) {
const data = await this.adminService.getDoctors();
return { success: true, data };
}

View File

@ -20,6 +20,8 @@ import {
ApiQuery,
} from '@nestjs/swagger';
import { PaginationDto } from '../common/dto/pagination.dto';
@ApiTags('Admin - مدیریت مقالات (بلاگ)')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ -32,7 +34,7 @@ export class BlogsController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getBlogs(@Query() query: BlogQuery) {
async getBlogs(@Query() query: PaginationDto) {
return this.blogsService.getBlogs(query);
}

View File

@ -19,6 +19,8 @@ import {
ApiQuery,
} from '@nestjs/swagger';
import { PaginationDto } from '../common/dto/pagination.dto';
@ApiTags('Admin - مدیریت دسته‌بندی‌ها')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ -31,7 +33,7 @@ export class CategoriesController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو در نام' })
async getCategories(@Query() query: CategoryQuery) {
async getCategories(@Query() query: PaginationDto) {
return this.categoriesService.getCategories(query);
}

View File

@ -0,0 +1,20 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString, IsEnum } from 'class-validator';
import { PaginationDto, SortOrder } from '../../common/dto/pagination.dto';
export class AdminQueryDto extends PaginationDto {
@ApiPropertyOptional({ description: 'فیلتر بر اساس نقش کاربر' })
@IsOptional()
@IsString()
role?: string;
@ApiPropertyOptional({ description: 'فیلتر بر اساس دسته‌بندی' })
@IsOptional()
@IsString()
categoryId?: string;
@ApiPropertyOptional({ description: 'فیلتر بر اساس وضعیت' })
@IsOptional()
@IsString()
status?: string;
}

View File

@ -15,6 +15,8 @@ import {
ApiQuery,
} from '@nestjs/swagger';
import { PaginationDto } from '../common/dto/pagination.dto';
@ApiTags('Admin - مدیریت حیوانات خانگی')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ -27,7 +29,7 @@ export class PetsController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getPets(@Query() query: PetQuery) {
async getPets(@Query() query: PaginationDto) {
return this.petsService.getPets(query);
}

View File

@ -19,6 +19,8 @@ import {
ApiQuery,
} from '@nestjs/swagger';
import { PaginationDto } from '../common/dto/pagination.dto';
@ApiTags('Admin - مدیریت دانشنامه (اصطلاحات علمی)')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ -31,7 +33,7 @@ export class WikiController {
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getTerms(@Query() query: WikiQuery) {
async getTerms(@Query() query: PaginationDto) {
return this.wikiService.getTerms(query);
}

View File

@ -5,6 +5,7 @@ import {
Put,
Body,
Param,
Query,
UseGuards,
Req,
} from '@nestjs/common';
@ -14,6 +15,8 @@ import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RolesGuard } from '../auth/roles.guard';
import { Roles } from '../auth/roles.decorator';
import { PaginationDto } from '../common/dto/pagination.dto';
@ApiTags('B2B - مدیریت پنل B2B و درخواست‌ها')
@Controller('b2b')
export class B2BController {
@ -41,7 +44,7 @@ export class B2BController {
@ApiBearerAuth()
@Get('inquiries')
@ApiOperation({ summary: 'لیست تمام استعلام‌های B2B (مخصوص ادمین)' })
findAllInquiries() {
findAllInquiries(@Query() query: PaginationDto) {
return this.b2bService.findAllInquiries();
}
@ -83,7 +86,7 @@ export class B2BController {
@ApiBearerAuth()
@Get('partners')
@ApiOperation({ summary: 'لیست حساب‌های همکاران تجاری (مخصوص ادمین)' })
getAllPartnerAccounts() {
getAllPartnerAccounts(@Query() query: PaginationDto) {
return this.b2bService.getAllPartnerAccounts();
}
}

View File

@ -61,7 +61,7 @@ async function bootstrap() {
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: false,
forbidNonWhitelisted: true,
exceptionFactory: (errors) => {
const formattedDetails = errors.map((err) => {
const constraints = err.constraints

View File

@ -8,6 +8,11 @@ export class GetProductsDto extends PaginationDto {
@IsString()
category?: string;
@ApiPropertyOptional({ description: 'فیلتر بر اساس آی‌دی دسته‌بندی' })
@IsOptional()
@IsString()
categoryId?: string;
@ApiPropertyOptional({
description: 'فیلتر بر اساس نوع حیوان',
enum: ['سگ', 'گربه', 'all'],

View File

@ -6,6 +6,7 @@ import {
Delete,
Body,
Param,
Query,
UseGuards,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';
@ -15,6 +16,8 @@ import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RolesGuard } from '../common/guards/roles.guard';
import { Roles } from '../common/decorators/roles.decorator';
import { PaginationDto } from '../common/dto/pagination.dto';
@ApiTags('Smart Advisor - دستیار هوشمند توصیه دارویی')
@Controller('smart-advisor/rules')
export class SmartAdvisorController {
@ -22,7 +25,7 @@ export class SmartAdvisorController {
@Get()
@ApiOperation({ summary: 'لیست قانون‌های دستیار هوشمند' })
findAll() {
findAll(@Query() query: PaginationDto) {
return this.smartAdvisorService.findAll();
}