From 7b6b79dfa809cd10a1b4fd2cab80e4b6a7318d11 Mon Sep 17 00:00:00 2001 From: mahyargdz Date: Wed, 20 Aug 2025 09:26:43 +0330 Subject: [PATCH] update: remove the auth guard from the feedback route --- src/common/decorators/rate-limit.decorator.ts | 11 +++++++++++ src/modules/auth/auth.controller.ts | 12 +++++------- .../DTO/create-service-feedback.dto.ts | 19 ++++++++++++++++--- .../danak-services.controller.ts | 3 ++- .../entities/danak-service-feedback.entity.ts | 6 ++++++ src/modules/users/providers/users.service.ts | 2 +- 6 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 src/common/decorators/rate-limit.decorator.ts diff --git a/src/common/decorators/rate-limit.decorator.ts b/src/common/decorators/rate-limit.decorator.ts new file mode 100644 index 0000000..59bbaca --- /dev/null +++ b/src/common/decorators/rate-limit.decorator.ts @@ -0,0 +1,11 @@ +import { UseGuards, applyDecorators } from "@nestjs/common"; +import { Throttle, ThrottlerGuard } from "@nestjs/throttler"; + +import { AUTH_THROTTLE_LIMIT, AUTH_THROTTLE_TTL, AUTH__REFRESH_THROTTLE_LIMIT, AUTH__REFRESH_THROTTLE_TTL } from "../constants"; + +export const RateLimit = (limit: number, ttl: number) => applyDecorators(Throttle({ default: { limit, ttl } }), UseGuards(ThrottlerGuard)); + +export const StrictRateLimit = () => RateLimit(AUTH_THROTTLE_LIMIT, AUTH_THROTTLE_TTL); // 5 requests per minute +export const StandardRateLimit = () => RateLimit(20, 60000); // 20 requests per minute +export const MailSendRateLimit = () => RateLimit(10, 60000); // 10 emails per minute +export const RefreshTokenRateLimit = () => RateLimit(AUTH__REFRESH_THROTTLE_LIMIT, AUTH__REFRESH_THROTTLE_TTL); // 10 refresh tokens per minute diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index 2162e55..7a29346 100755 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -1,25 +1,23 @@ -import { Body, Controller, HttpCode, HttpStatus, Patch, Post, UseGuards } from "@nestjs/common"; +import { Body, Controller, HttpCode, HttpStatus, Patch, Post } from "@nestjs/common"; import { ApiOperation, ApiTags } from "@nestjs/swagger"; -import { Throttle, ThrottlerGuard } from "@nestjs/throttler"; import { ChangePasswordDto } from "./DTO/change-password.dto"; import { CheckUserExistDto, LoginPasswordDTO } from "./DTO/loginPassword.dto"; import { RefreshTokenDto } from "./DTO/refresh-token.dto"; import { RequestOtpDto } from "./DTO/request-otp.dto"; import { SSOTokenRequestDTO } from "./DTO/requests/sso-token-request.dto"; +import { SSOTokenValidateDTO } from "./DTO/requests/sso-token-validate.dto"; import { VerifyOtpDto } from "./DTO/verify-otp.dto"; import { AuthService } from "./providers/auth.service"; import { SSOService } from "./providers/sso.service"; -import { AUTH_THROTTLE_LIMIT, AUTH_THROTTLE_TTL, AUTH__REFRESH_THROTTLE_LIMIT, AUTH__REFRESH_THROTTLE_TTL } from "../../common/constants"; -import { SSOTokenValidateDTO } from "./DTO/requests/sso-token-validate.dto"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; +import { RefreshTokenRateLimit, StrictRateLimit } from "../../common/decorators/rate-limit.decorator"; import { UserDec } from "../../common/decorators/user.decorator"; import { User } from "../users/entities/user.entity"; @ApiTags("Auth") @Controller("auth") -@Throttle({ default: { limit: AUTH_THROTTLE_LIMIT, ttl: AUTH_THROTTLE_TTL } }) -@UseGuards(ThrottlerGuard) +@StrictRateLimit() export class AuthController { constructor( private readonly authService: AuthService, @@ -77,7 +75,7 @@ export class AuthController { return this.authService.changePassword(userId, changePasswordDto); } - @Throttle({ default: { limit: AUTH__REFRESH_THROTTLE_LIMIT, ttl: AUTH__REFRESH_THROTTLE_TTL } }) + @RefreshTokenRateLimit() @ApiOperation({ summary: "refresh the user access token / refresh token" }) @HttpCode(HttpStatus.OK) @Post("refresh") diff --git a/src/modules/danak-services/DTO/create-service-feedback.dto.ts b/src/modules/danak-services/DTO/create-service-feedback.dto.ts index 981ff99..29888d5 100644 --- a/src/modules/danak-services/DTO/create-service-feedback.dto.ts +++ b/src/modules/danak-services/DTO/create-service-feedback.dto.ts @@ -1,7 +1,7 @@ import { ApiProperty } from "@nestjs/swagger"; -import { IsIn, IsInt, IsNotEmpty, IsString, IsUUID, Length } from "class-validator"; +import { IsEmail, IsIn, IsInt, IsMobilePhone, IsNotEmpty, IsOptional, IsString, IsUUID, Length } from "class-validator"; -import { ServiceMessage, UserMessage } from "../../../common/enums/message.enum"; +import { AuthMessage, ServiceMessage, UserMessage } from "../../../common/enums/message.enum"; export class CreateServiceFeedbackDto { @IsNotEmpty({ message: ServiceMessage.COMMENT_REQUIRED }) @@ -21,8 +21,21 @@ export class CreateServiceFeedbackDto { @ApiProperty({ description: "Service ID", example: "d290f1ee-6c54-4b01-90e6-d701748f0851" }) serviceId: string; + @IsOptional() @IsNotEmpty({ message: UserMessage.USER_ID_REQUIRED }) @IsUUID("all", { message: UserMessage.USER_ID_SHOULD_BE_A_UUID }) @ApiProperty({ description: "User ID", example: "d290f1ee-6c54-4b01-90e6-d701748f0851" }) - userId: string; + userId?: string; + + @IsOptional() + @IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY }) + @IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT }) + @ApiProperty({ description: "User Phone", example: "+989123456789" }) + phone?: string; + + @IsOptional() + @IsNotEmpty({ message: AuthMessage.EMAIL_NOT_EMPTY }) + @IsEmail({}, { message: AuthMessage.INVALID_EMAIL_FORMAT }) + @ApiProperty({ description: "User Email", example: "example@example.com" }) + email: string; } diff --git a/src/modules/danak-services/danak-services.controller.ts b/src/modules/danak-services/danak-services.controller.ts index 96735d6..d69c38c 100755 --- a/src/modules/danak-services/danak-services.controller.ts +++ b/src/modules/danak-services/danak-services.controller.ts @@ -20,6 +20,7 @@ import { DanakServicesService } from "./providers/danak-services.service"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { Pagination } from "../../common/decorators/pagination.decorator"; import { PermissionsDec } from "../../common/decorators/permission.decorator"; +import { StrictRateLimit } from "../../common/decorators/rate-limit.decorator"; import { UserDec } from "../../common/decorators/user.decorator"; import { ParamDto } from "../../common/DTO/param.dto"; import { PermissionEnum } from "../users/enums/permission.enum"; @@ -270,7 +271,7 @@ export class DanakServicesController { //------------------------ service feedback ------------------------ @ApiOperation({ summary: "Create service feedback => user route" }) - @AuthGuards() + @StrictRateLimit() @Post("feedback") createServiceFeedback(@Body() createDto: CreateServiceFeedbackDto, @Headers() headers: Record, @Ip() ip: string) { return this.danakServicesService.createServiceFeedback(createDto, headers, ip); diff --git a/src/modules/danak-services/entities/danak-service-feedback.entity.ts b/src/modules/danak-services/entities/danak-service-feedback.entity.ts index 92f6b37..f51c190 100644 --- a/src/modules/danak-services/entities/danak-service-feedback.entity.ts +++ b/src/modules/danak-services/entities/danak-service-feedback.entity.ts @@ -18,6 +18,12 @@ export class DanakServiceFeedback extends BaseEntity { @ManyToOne(() => User, (user) => user.serviceFeedbacks, { onDelete: "SET NULL", nullable: true }) user: User | null; + @Column({ type: "varchar", nullable: true }) + phone: string | null; + + @Column({ type: "varchar", nullable: true }) + email: string | null; + @ManyToOne(() => DanakService, (service) => service.feedbacks, { onDelete: "CASCADE", nullable: false }) service: DanakService; diff --git a/src/modules/users/providers/users.service.ts b/src/modules/users/providers/users.service.ts index ce9350e..10f043e 100755 --- a/src/modules/users/providers/users.service.ts +++ b/src/modules/users/providers/users.service.ts @@ -249,7 +249,7 @@ export class UsersService { const userName = slugify(`u-${registerDto.phone}`, { lower: true, trim: true }); const defaultFirstName = "کاربر"; - const defaultLastName = userName.slice(0, 5); + const defaultLastName = userName; const { referralCode, ...userData } = registerDto; const user = queryRunner.manager.create(User, {