chore: add register of user
This commit is contained in:
+6
-1
@@ -18,6 +18,12 @@
|
|||||||
"test:cov": "jest --coverage",
|
"test:cov": "jest --coverage",
|
||||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||||
|
"typeorm": "node -r ts-node/register ./node_modules/typeorm/cli",
|
||||||
|
"migration:run": "npx typeorm-ts-node-commonjs migration:run -d ./database/connection.ts",
|
||||||
|
"migration:generate": "npx typeorm-ts-node-commonjs migration:generate -d ./database/connection.ts ./database/migrations/$npm_config_name",
|
||||||
|
"migration:create": "npx typeorm-ts-node-commonjs migration:create ./database/migrations/$npm_config_name",
|
||||||
|
"migration:revert": "npx typeorm-ts-node-commonjs migration:revert -d ./database/connection.ts",
|
||||||
|
"migration:show": "npx typeorm-ts-node-commonjs migration:show -d ./database/connection.ts ",
|
||||||
"prepare": "husky || true"
|
"prepare": "husky || true"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -25,7 +31,6 @@
|
|||||||
"@keyv/redis": "^4.2.0",
|
"@keyv/redis": "^4.2.0",
|
||||||
"@nestjs-modules/mailer": "^2.0.2",
|
"@nestjs-modules/mailer": "^2.0.2",
|
||||||
"@nestjs/cache-manager": "^3.0.0",
|
"@nestjs/cache-manager": "^3.0.0",
|
||||||
"@nestjs/class-validator": "^0.13.4",
|
|
||||||
"@nestjs/common": "^10.4.15",
|
"@nestjs/common": "^10.4.15",
|
||||||
"@nestjs/config": "^4.0.0",
|
"@nestjs/config": "^4.0.0",
|
||||||
"@nestjs/core": "^10.4.15",
|
"@nestjs/core": "^10.4.15",
|
||||||
|
|||||||
Generated
-11
@@ -20,9 +20,6 @@ importers:
|
|||||||
'@nestjs/cache-manager':
|
'@nestjs/cache-manager':
|
||||||
specifier: ^3.0.0
|
specifier: ^3.0.0
|
||||||
version: 3.0.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1))(cache-manager@6.3.2)(rxjs@7.8.1)
|
version: 3.0.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1))(cache-manager@6.3.2)(rxjs@7.8.1)
|
||||||
'@nestjs/class-validator':
|
|
||||||
specifier: ^0.13.4
|
|
||||||
version: 0.13.4
|
|
||||||
'@nestjs/common':
|
'@nestjs/common':
|
||||||
specifier: ^10.4.15
|
specifier: ^10.4.15
|
||||||
version: 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
version: 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||||
@@ -713,9 +710,6 @@ packages:
|
|||||||
cache-manager: '>=6'
|
cache-manager: '>=6'
|
||||||
rxjs: ^7.8.1
|
rxjs: ^7.8.1
|
||||||
|
|
||||||
'@nestjs/class-validator@0.13.4':
|
|
||||||
resolution: {integrity: sha512-/mqZL36LJ5uV5WDhi87Cd52IssuO+SStaOr2+6sBsvCCGUWkoJes4Wwzmm3m/gdHH+tsNxX60sVSzYcU6hAy9Q==}
|
|
||||||
|
|
||||||
'@nestjs/cli@10.4.9':
|
'@nestjs/cli@10.4.9':
|
||||||
resolution: {integrity: sha512-s8qYd97bggqeK7Op3iD49X2MpFtW4LVNLAwXFkfbRxKME6IYT7X0muNTJ2+QfI8hpbNx9isWkrLWIp+g5FOhiA==}
|
resolution: {integrity: sha512-s8qYd97bggqeK7Op3iD49X2MpFtW4LVNLAwXFkfbRxKME6IYT7X0muNTJ2+QfI8hpbNx9isWkrLWIp+g5FOhiA==}
|
||||||
engines: {node: '>= 16.14'}
|
engines: {node: '>= 16.14'}
|
||||||
@@ -5459,11 +5453,6 @@ snapshots:
|
|||||||
cache-manager: 6.3.2
|
cache-manager: 6.3.2
|
||||||
rxjs: 7.8.1
|
rxjs: 7.8.1
|
||||||
|
|
||||||
'@nestjs/class-validator@0.13.4':
|
|
||||||
dependencies:
|
|
||||||
libphonenumber-js: 1.11.18
|
|
||||||
validator: 13.12.0
|
|
||||||
|
|
||||||
'@nestjs/cli@10.4.9':
|
'@nestjs/cli@10.4.9':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@angular-devkit/core': 17.3.11(chokidar@3.6.0)
|
'@angular-devkit/core': 17.3.11(chokidar@3.6.0)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { TypeOrmModule } from "@nestjs/typeorm";
|
|||||||
import { cacheConfig } from "./configs/cache.config";
|
import { cacheConfig } from "./configs/cache.config";
|
||||||
import { DatabaseConfigs } from "./configs/typeorm.config";
|
import { DatabaseConfigs } from "./configs/typeorm.config";
|
||||||
import { HTTPLogger } from "./core/middlewares/logger.middleware";
|
import { HTTPLogger } from "./core/middlewares/logger.middleware";
|
||||||
|
import { AuthModule } from "./modules/auth/auth.module";
|
||||||
import { TicketsModule } from "./modules/tickets/tickets.module";
|
import { TicketsModule } from "./modules/tickets/tickets.module";
|
||||||
import { UsersModule } from "./modules/users/users.module";
|
import { UsersModule } from "./modules/users/users.module";
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ import { UsersModule } from "./modules/users/users.module";
|
|||||||
TypeOrmModule.forRootAsync(DatabaseConfigs()),
|
TypeOrmModule.forRootAsync(DatabaseConfigs()),
|
||||||
UsersModule,
|
UsersModule,
|
||||||
TicketsModule,
|
TicketsModule,
|
||||||
|
AuthModule,
|
||||||
],
|
],
|
||||||
controllers: [],
|
controllers: [],
|
||||||
providers: [],
|
providers: [],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const enum AuthMessage {
|
export const enum AuthMessage {
|
||||||
PHONE_REGISTERED = "شماره ثبت شد",
|
PHONE_REGISTERED = "شماره ثبت شد",
|
||||||
INVALID_NEZAM_PHONE = "شماره موبایل وارد نامعتبر می باشد",
|
INVALID_PHONE_FORMAT = "فرمت شماره تلفن صحیح نیست",
|
||||||
OTP_SENT = "کد یکبار مصرف به شماره شما ارسال شد.",
|
OTP_SENT = "کد یکبار مصرف به شماره شما ارسال شد.",
|
||||||
INVALID_PHONE = "شماره موبایل اشتباه می باشد",
|
INVALID_PHONE = "شماره موبایل اشتباه می باشد",
|
||||||
INVALID_CREDENTIAL = "شماره موبایل یا رمز عبور اشتباه می باشد",
|
INVALID_CREDENTIAL = "شماره موبایل یا رمز عبور اشتباه می باشد",
|
||||||
@@ -10,11 +10,11 @@ export const enum AuthMessage {
|
|||||||
FORGOT_PASSWORD_SUCCESS = "درخواست فراموشی رمز عبور با موفقیت ثبت شد",
|
FORGOT_PASSWORD_SUCCESS = "درخواست فراموشی رمز عبور با موفقیت ثبت شد",
|
||||||
PASSWORD_SET_SUCCESS = "پسورد با موفقیت تنظیم شد",
|
PASSWORD_SET_SUCCESS = "پسورد با موفقیت تنظیم شد",
|
||||||
PASSWORD_UPDATE_SUCCESS = "رمز عبور شما تغییر کرد",
|
PASSWORD_UPDATE_SUCCESS = "رمز عبور شما تغییر کرد",
|
||||||
INVALID_OTP = "کد صحیح نمیباشد",
|
INVALID_OTP = "کد صحیح نمیباشد یا منقضی شده است",
|
||||||
PASSWORD_MISMATCH = "رمز عبور یکسان نیست",
|
PASSWORD_MISMATCH = "رمز عبور یکسان نیست",
|
||||||
INVALID_PASSWORD = "ایمیل یا رمز عبور اشتباه است",
|
INVALID_PASSWORD = "ایمیل یا رمز عبور اشتباه است",
|
||||||
EmailNotEmpty = "ایمیل نمیتواند خالی باشد.",
|
EMAIL_NOT_EMPTY = "ایمیل نمیتواند خالی باشد.",
|
||||||
IncorrectEmail = "ایمیل صحیح نیست",
|
INVALID_EMAIL_FORMAT = "فرمت ایمیل صحیح نیست",
|
||||||
PasswordNotEmpty = "پسورد نمیتواند خالی باشد.",
|
PasswordNotEmpty = "پسورد نمیتواند خالی باشد.",
|
||||||
USER_NOT_FOUND = "کاربری با این شماره وجود ندارد",
|
USER_NOT_FOUND = "کاربری با این شماره وجود ندارد",
|
||||||
USER_EXISTS = "با این شماره قبلا ثبت نام شده است",
|
USER_EXISTS = "با این شماره قبلا ثبت نام شده است",
|
||||||
@@ -23,13 +23,32 @@ export const enum AuthMessage {
|
|||||||
PHONE_NOT_FOUND = "کاربری با این آیدی یافت نشد",
|
PHONE_NOT_FOUND = "کاربری با این آیدی یافت نشد",
|
||||||
TOKEN_EXPIRED = "توکن منقضی شده است",
|
TOKEN_EXPIRED = "توکن منقضی شده است",
|
||||||
TOKEN_INVALID = "توکن نامعتبر است",
|
TOKEN_INVALID = "توکن نامعتبر است",
|
||||||
Banned = "در حال حاضر شما امکان دسترسی به این سرویس را ندارید",
|
BANNED = "در حال حاضر شما امکان دسترسی به این سرویس را ندارید",
|
||||||
PHONE_EXISTS = "شماره تلفن قبلا ثبت شده است",
|
PHONE_EXISTS = "شماره تلفن قبلا ثبت شده است",
|
||||||
ADMIN_CREATED = "ادمین با موفقیت ایجاد شد",
|
ADMIN_CREATED = "ادمین با موفقیت ایجاد شد",
|
||||||
Permission_NOT_FOUND = "دسترسی یافت نشد",
|
PERM_NOT_FOUND = "دسترسی یافت نشد",
|
||||||
ADMIN_NOT_FOUND = "ادمین یافت نشد",
|
ADMIN_NOT_FOUND = "ادمین یافت نشد",
|
||||||
|
INVALID_PASS_FORMAT = "فرمت رمز عبور صحیح نیست",
|
||||||
|
PHONE_NOT_EMPTY = "شماره تلفن نمیتواند خالی باشد",
|
||||||
|
PASSWORD_FORMAT_INVALID = "رمز عبور باید به صورت رشته باشد",
|
||||||
|
OTP_FORMAT_INVALID = "کد یکبار مصرف باید عددی و ۵ رقمی باشد",
|
||||||
|
PHONE_FORMAT_INVALID = "شماره تلفن باید معتبر و به فرمت ایران باشد",
|
||||||
|
TOKEN_NOT_EMPTY = "توکن نمیتواند خالی باشد",
|
||||||
|
PASSWORD_NOT_EMPTY = "رمز عبور نمیتواند خالی باشد",
|
||||||
|
PASSWORD_CONFIRMATION_NOT_EMPTY = "تایید رمز عبور نمیتواند خالی باشد",
|
||||||
|
PASSWORD_LENGTH = "رمز عبور باید حداقل ۸ کاراکتر باشد",
|
||||||
|
OTP_NOT_EMPTY = "کد یکبار مصرف نمیتواند خالی باشد",
|
||||||
|
LAST_PASSWORD_NOT_EMPTY = "رمز عبور قبلی نمیتواند خالی باشد",
|
||||||
|
FIRST_NAME_NOT_EMPTY = "نام نمیتواند خالی باشد",
|
||||||
|
LAST_NAME_NOT_EMPTY = "نام خانوادگی نمیتواند خالی باشد",
|
||||||
|
FIRST_NAME_SHOULD_BE_BETWEEN_2_AND_50 = "نام باید بین ۲ تا ۵۰ کاراکتر باشد",
|
||||||
|
LAST_NAME_SHOULD_BE_BETWEEN_2_AND_50 = "نام خانوادگی باید بین ۲ تا ۵۰ کاراکتر باشد",
|
||||||
|
BIRTH_DATE_NOT_EMPTY = "تاریخ تولد نمیتواند خالی باشد",
|
||||||
|
NATIONAL_CODE_INCORRECT = "کد ملی باید ۱۰ رقمی باشد",
|
||||||
|
NATIONAL_NOT_EMPTY = "کد ملی نمیتواند خالی باشد",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum UserMessage {
|
export const enum UserMessage {
|
||||||
USER_NOT_FOUND = "کاربری با این مشخصات یافت نشد",
|
USER_NOT_FOUND = "کاربری با این مشخصات یافت نشد",
|
||||||
|
EMAIL_EXIST = "ایمیل قبلا ثبت شده است",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ export function SmsConfigs() {
|
|||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
useFactory(configService: ConfigService) {
|
useFactory(configService: ConfigService) {
|
||||||
return {
|
return {
|
||||||
URL: configService.getOrThrow<string>("URL"),
|
API_URL: configService.getOrThrow<string>("SMS_API_URL"),
|
||||||
API_KEY: configService.getOrThrow<string>("API_KEY"),
|
API_KEY: configService.getOrThrow<string>("SMS_API_KEY"),
|
||||||
SECRET_KEY: configService.getOrThrow<string>("SECRET_KEY"),
|
SECRET_KEY: configService.getOrThrow<string>("SMS_SECRET"),
|
||||||
SMS_PATTERN_OTP: configService.getOrThrow<string>("SMS_PATTERN_OTP"),
|
SMS_PATTERN_OTP: configService.getOrThrow<string>("SMS_PATTERN_OTP"),
|
||||||
SMS_SECRET_BODY: {
|
// SMS_SECRET_BODY: {
|
||||||
UserApiKey: configService.getOrThrow<string>("API_KEY"),
|
// UserApiKey: configService.getOrThrow<string>("SMS_API_KEY"),
|
||||||
SecretKey: configService.getOrThrow<string>("SECRET_KEY"),
|
// SecretKey: configService.getOrThrow<string>("SECRET_KEY"),
|
||||||
},
|
// },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsEmail, IsMobilePhone, IsNotEmpty, IsNumberString, IsString, Length, MinLength } from "class-validator";
|
||||||
|
|
||||||
|
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export class CompleteRegistrationDto {
|
||||||
|
@IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY })
|
||||||
|
@IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT })
|
||||||
|
@ApiProperty({ description: "phone number", default: "09123456789" })
|
||||||
|
phone: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "OTP code received via SMS", example: "56893" })
|
||||||
|
@IsNotEmpty({ message: AuthMessage.OTP_NOT_EMPTY })
|
||||||
|
@IsNumberString(undefined, { message: AuthMessage.OTP_FORMAT_INVALID })
|
||||||
|
@Length(5, 5, { message: AuthMessage.OTP_FORMAT_INVALID })
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
|
||||||
|
@IsString({ message: AuthMessage.FIRST_NAME_NOT_EMPTY })
|
||||||
|
@Length(2, 50, { message: AuthMessage.FIRST_NAME_SHOULD_BE_BETWEEN_2_AND_50 })
|
||||||
|
@ApiProperty({ description: "First name", example: "mahyar" })
|
||||||
|
firstName: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: AuthMessage.LAST_NAME_NOT_EMPTY })
|
||||||
|
@IsString({ message: AuthMessage.LAST_NAME_NOT_EMPTY })
|
||||||
|
@Length(2, 50, { message: AuthMessage.LAST_NAME_SHOULD_BE_BETWEEN_2_AND_50 })
|
||||||
|
@ApiProperty({ description: "Last name", example: "jamshidi" })
|
||||||
|
lastName: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: AuthMessage.EMAIL_NOT_EMPTY })
|
||||||
|
@IsEmail({}, { message: AuthMessage.INVALID_EMAIL_FORMAT })
|
||||||
|
@ApiProperty({ description: "Email", example: "ma@gmail.com" })
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: AuthMessage.BIRTH_DATE_NOT_EMPTY })
|
||||||
|
@IsString({ message: AuthMessage.BIRTH_DATE_NOT_EMPTY })
|
||||||
|
@ApiProperty({ description: "Birth date", example: "1403/01/01" })
|
||||||
|
birthDate: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: AuthMessage.NATIONAL_NOT_EMPTY })
|
||||||
|
@IsNumberString({ no_symbols: true }, { message: AuthMessage.NATIONAL_CODE_INCORRECT })
|
||||||
|
@Length(10, 10, { message: AuthMessage.NATIONAL_CODE_INCORRECT })
|
||||||
|
@ApiProperty({ description: "iranian format (10 char)", example: "4569852169" })
|
||||||
|
nationalCode: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: AuthMessage.PASSWORD_NOT_EMPTY })
|
||||||
|
@IsString({ message: AuthMessage.PASSWORD_FORMAT_INVALID })
|
||||||
|
@ApiProperty({ description: "password", example: "12S345SS678" })
|
||||||
|
@MinLength(8, { message: AuthMessage.PASSWORD_LENGTH })
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
+7
-5
@@ -1,14 +1,16 @@
|
|||||||
import { IsEmail, IsNotEmpty } from "@nestjs/class-validator";
|
|
||||||
import { AuthMessage } from "../../../common/enums/message.enum";
|
|
||||||
import { ApiProperty } from "@nestjs/swagger";
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsEmail, IsNotEmpty, IsString } from "class-validator";
|
||||||
|
|
||||||
|
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
export class LoginPasswordDTO {
|
export class LoginPasswordDTO {
|
||||||
@IsNotEmpty({ message: AuthMessage.EmailNotEmpty })
|
@IsNotEmpty({ message: AuthMessage.EMAIL_NOT_EMPTY })
|
||||||
@IsEmail(undefined, { message: AuthMessage.IncorrectEmail })
|
@IsEmail(undefined, { message: AuthMessage.INVALID_EMAIL_FORMAT })
|
||||||
@ApiProperty({ description: "email of user", default: "user@abrclick.ir" })
|
@ApiProperty({ description: "email of user", default: "user@test.ir" })
|
||||||
email: string;
|
email: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: AuthMessage.PasswordNotEmpty })
|
@IsNotEmpty({ message: AuthMessage.PasswordNotEmpty })
|
||||||
|
@IsString({ message: AuthMessage.INVALID_PASS_FORMAT })
|
||||||
@ApiProperty({ type: "string", description: "password user", example: "@1234" })
|
@ApiProperty({ type: "string", description: "password user", example: "@1234" })
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsMobilePhone, IsNotEmpty } from "class-validator";
|
||||||
|
|
||||||
|
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export class RequestOtpDto {
|
||||||
|
@IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY })
|
||||||
|
@IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT })
|
||||||
|
@ApiProperty({ description: "phone number", default: "09123456789" })
|
||||||
|
phone: string;
|
||||||
|
}
|
||||||
@@ -1,4 +1,49 @@
|
|||||||
import { Controller } from "@nestjs/common";
|
import { Body, Controller, Post } from "@nestjs/common";
|
||||||
|
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||||
|
|
||||||
|
import { AuthService } from "./auth.service";
|
||||||
|
import { CompleteRegistrationDto } from "./DTO/complete-register.dto";
|
||||||
|
import { RequestOtpDto } from "./DTO/request-otp.dto";
|
||||||
|
|
||||||
|
@ApiTags("Auth")
|
||||||
@Controller("auth")
|
@Controller("auth")
|
||||||
export class AuthController {}
|
export class AuthController {
|
||||||
|
constructor(private authService: AuthService) {}
|
||||||
|
|
||||||
|
@ApiOperation({ summary: "Initiate registration" })
|
||||||
|
@Post("register/initiate")
|
||||||
|
async register(@Body() registerDto: RequestOtpDto) {
|
||||||
|
return this.authService.initiateRegistration(registerDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation({ summary: "complete registration ==> step 2" })
|
||||||
|
@Post("register/complete")
|
||||||
|
async completeRegistration(@Body() completeRegistrationDto: CompleteRegistrationDto) {
|
||||||
|
return this.authService.completeRegistration(completeRegistrationDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Post("login")
|
||||||
|
// async login(@Body() loginDto: LoginDto) {
|
||||||
|
// return this.authService.login(loginDto);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Post("otp/register/send")
|
||||||
|
// async sendOtp(@Body() sendOtpDto: RequestOtpDto) {
|
||||||
|
// return this.authService.requestRegisterOTP(sendOtpDto);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Post("otp/verify")
|
||||||
|
// async verifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
|
||||||
|
// return this.authService.verifyOtp(verifyOtpDto);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Post("forgot-password")
|
||||||
|
// async forgotPassword(@Body() forgotPasswordDto: ForgotPasswordDto) {
|
||||||
|
// return this.authService.forgotPassword(forgotPasswordDto);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Post("reset-password")
|
||||||
|
// async resetPassword(@Body() resetPasswordDto: ResetPasswordDto) {
|
||||||
|
// return this.authService.resetPassword(resetPasswordDto);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import { Module } from "@nestjs/common";
|
|||||||
|
|
||||||
import { AuthController } from "./auth.controller";
|
import { AuthController } from "./auth.controller";
|
||||||
import { AuthService } from "./auth.service";
|
import { AuthService } from "./auth.service";
|
||||||
|
import { UsersModule } from "../users/users.module";
|
||||||
import { UtilsModule } from "../utils/utils.module";
|
import { UtilsModule } from "../utils/utils.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [UtilsModule],
|
imports: [UtilsModule, UsersModule],
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
providers: [AuthService],
|
providers: [AuthService],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,20 +1,55 @@
|
|||||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||||
import { UsersService } from "../users/providers/users.service";
|
|
||||||
import { LoginPasswordDTO } from "./DTOs/loginPassword.dto";
|
import { CompleteRegistrationDto } from "./DTO/complete-register.dto";
|
||||||
import { PasswordService } from "../utils/providers/password.service";
|
import { LoginPasswordDTO } from "./DTO/loginPassword.dto";
|
||||||
|
import { RequestOtpDto } from "./DTO/request-otp.dto";
|
||||||
import { AuthMessage, UserMessage } from "../../common/enums/message.enum";
|
import { AuthMessage, UserMessage } from "../../common/enums/message.enum";
|
||||||
|
import { UsersService } from "../users/providers/users.service";
|
||||||
|
import { OTPService } from "../utils/providers/otp.service";
|
||||||
|
import { PasswordService } from "../utils/providers/password.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
|
private readonly logger = new Logger(AuthService.name);
|
||||||
constructor(
|
constructor(
|
||||||
private readonly userSerivce: UsersService,
|
private readonly userService: UsersService,
|
||||||
private readonly passwordService: PasswordService,
|
private readonly passwordService: PasswordService,
|
||||||
|
private readonly otpService: OTPService,
|
||||||
) {}
|
) {}
|
||||||
|
//****************** */
|
||||||
|
async initiateRegistration(requestOtpDto: RequestOtpDto) {
|
||||||
|
const { phone } = requestOtpDto;
|
||||||
|
const otpCode = await this.otpService.generateAndSetInCache(phone, "REGISTER");
|
||||||
|
// await SmsService.sendOtp(phone, otpCode);
|
||||||
|
this.logger.log(`OTP sent to ${phone}: ${otpCode}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: AuthMessage.OTP_SENT,
|
||||||
|
otpCode,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//****************** */
|
||||||
|
async completeRegistration(completeRegistrationDto: CompleteRegistrationDto) {
|
||||||
|
const { phone, code } = completeRegistrationDto;
|
||||||
|
const isValid = await this.otpService.verifyOtp(phone, code, "REGISTER");
|
||||||
|
|
||||||
|
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
|
||||||
|
|
||||||
|
await this.otpService.delOtpFormCache(phone, "REGISTER");
|
||||||
|
const hashedPassword = await this.passwordService.hashPassword(completeRegistrationDto.password);
|
||||||
|
const user = await this.userService.createUser(completeRegistrationDto, hashedPassword);
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: AuthMessage.USER_REGISTER_SUCCESS,
|
||||||
|
user,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//****************** */
|
||||||
|
|
||||||
async loginWithPassword(loginDto: LoginPasswordDTO) {
|
async loginWithPassword(loginDto: LoginPasswordDTO) {
|
||||||
const { email, password } = loginDto;
|
const { email, password } = loginDto;
|
||||||
|
|
||||||
const user = await this.userSerivce.findOneWithEmail(email);
|
const user = await this.userService.findOneWithEmail(email);
|
||||||
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||||
|
|
||||||
const passCompare = await this.passwordService.comparePassword(password, user.password);
|
const passCompare = await this.passwordService.comparePassword(password, user.password);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export class UserRegisterDto {}
|
|
||||||
@@ -15,7 +15,7 @@ export class User extends BaseEntity {
|
|||||||
password: string;
|
password: string;
|
||||||
|
|
||||||
@Column({ type: "varchar", length: 150 })
|
@Column({ type: "varchar", length: 150 })
|
||||||
fistName: string;
|
firstName: string;
|
||||||
|
|
||||||
@Column({ type: "varchar", length: 200 })
|
@Column({ type: "varchar", length: 200 })
|
||||||
lastName: string;
|
lastName: string;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||||
|
|
||||||
import { UserRepository } from "./users.repository";
|
|
||||||
import { User } from "../entities/user.entity";
|
|
||||||
import { UserMessage } from "../../../common/enums/message.enum";
|
|
||||||
import { RoleRepository } from "./roles.repository";
|
import { RoleRepository } from "./roles.repository";
|
||||||
|
import { UserRepository } from "./users.repository";
|
||||||
import { roles } from "../../../../db/seeders/role.seeder";
|
import { roles } from "../../../../db/seeders/role.seeder";
|
||||||
|
import { UserMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto";
|
||||||
|
import { User } from "../entities/user.entity";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UsersService {
|
export class UsersService {
|
||||||
@@ -25,4 +26,12 @@ export class UsersService {
|
|||||||
this.logger.log({ createdRoles });
|
this.logger.log({ createdRoles });
|
||||||
return createdRoles;
|
return createdRoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createUser(registerDto: CompleteRegistrationDto, hashedPassword: string): Promise<User> {
|
||||||
|
const existEmail = await this.userRepository.findOneWithEmail(registerDto.email);
|
||||||
|
if (existEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST);
|
||||||
|
|
||||||
|
const user = this.userRepository.create({ ...registerDto, password: hashedPassword });
|
||||||
|
return await this.userRepository.save(user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export type OtpCacheKeyType = "LOGIN" | "REGISTER" | "FORGOT_PASSWORD";
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { randomInt } from "node:crypto";
|
import { randomInt } from "node:crypto";
|
||||||
|
|
||||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
import { CacheService } from "./cache.service";
|
import { CacheService } from "./cache.service";
|
||||||
import { AuthMessage } from "../../../common/enums/message.enum";
|
import { OtpCacheKeyType } from "../interfaces/IOtpKey";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OTPService {
|
export class OTPService {
|
||||||
@@ -13,17 +13,21 @@ export class OTPService {
|
|||||||
return randomInt(10000, 99999).toString();
|
return randomInt(10000, 99999).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateAndStore(identifier: string, cacheKey: string = "Login") {
|
async generateAndSetInCache(identifier: string, cacheKey: OtpCacheKeyType) {
|
||||||
const otp = this.generateOTP();
|
const otp = this.generateOTP();
|
||||||
const key = `${identifier}:${cacheKey}:OTP`;
|
const key = `${identifier}:${cacheKey}:OTP`;
|
||||||
await this.cacheService.set(key, otp);
|
await this.cacheService.set(key, otp);
|
||||||
|
return otp;
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyOtp(identifier: string, otpCode: string, cacheKey: string = "Login") {
|
async verifyOtp(identifier: string, otpCode: string, cacheKey: OtpCacheKeyType) {
|
||||||
const key = `${identifier}:${cacheKey}:Otp`;
|
const key = `${identifier}:${cacheKey}:OTP`;
|
||||||
const codeInCache = await this.cacheService.get(key);
|
const codeInCache = await this.cacheService.get<string | null>(key);
|
||||||
|
return codeInCache && otpCode === codeInCache;
|
||||||
|
}
|
||||||
|
|
||||||
if (!codeInCache || otpCode !== codeInCache) throw new BadRequestException(AuthMessage.INVALID_OTP);
|
async delOtpFormCache(identifier: string, cacheKey: OtpCacheKeyType) {
|
||||||
|
const key = `${identifier}:${cacheKey}:OTP`;
|
||||||
await this.cacheService.del(key);
|
await this.cacheService.del(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user