feat: add user createOne and refactor code
This commit is contained in:
@@ -6,6 +6,8 @@ import { OtpModule } from '../otp/otp.module';
|
||||
import { HashingModule } from '@/common/modules/hashing/hashing.module';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { LoginProvider } from './providers/login.provider';
|
||||
import { GenerateTokenProvider } from './providers/generate-token.provider';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -25,6 +27,6 @@ import { ConfigService } from '@nestjs/config';
|
||||
}),
|
||||
],
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService],
|
||||
providers: [AuthService, GenerateTokenProvider, LoginProvider],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Transform } from 'class-transformer';
|
||||
import { IsNotEmpty, IsOptional, IsString, Matches } from 'class-validator';
|
||||
import { i18nValidationMessage as t } from 'nestjs-i18n';
|
||||
|
||||
export class LoginDTO {
|
||||
export class PhoneDTO {
|
||||
@ApiProperty({
|
||||
type: 'string',
|
||||
description: `User's Phone Number`,
|
||||
@@ -24,7 +24,9 @@ export class LoginDTO {
|
||||
})
|
||||
@Transform(({ value }) => Utils.StringUtils.normalizePhone(value as string))
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export class LoginDTO extends PhoneDTO {
|
||||
@ApiProperty({
|
||||
type: 'string',
|
||||
description: 'Password for User Account',
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import { PhoneDTO } from './login.dto';
|
||||
import { i18nValidationMessage as t } from 'nestjs-i18n';
|
||||
|
||||
export class VerifyOtpDTO extends PhoneDTO {
|
||||
@IsString()
|
||||
@IsNotEmpty({
|
||||
message: t('validation.requiredField', {
|
||||
field: '$t(auth.fields.otp)',
|
||||
}),
|
||||
})
|
||||
otp: string;
|
||||
}
|
||||
@@ -2,6 +2,6 @@ POST http://localhost:3000/users/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"phone": "09333026363",
|
||||
"phone": "09126093033",
|
||||
"password": "rad1.3.5"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface AccessTokenPayload {
|
||||
sub: number;
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export interface RefreshTokenPayload {
|
||||
sub: number;
|
||||
jti: string;
|
||||
}
|
||||
@@ -1,88 +1,17 @@
|
||||
import { UsersService } from '@/modules/users/providers/users.service';
|
||||
import { Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { LoginDTO } from '../dtos/login.dto';
|
||||
import { OtpService } from '@/modules/otp/providers/otp.service';
|
||||
import { HashingProvider } from '@/common/modules/hashing/providers/hashing.provider';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import type { ConfigType } from '@nestjs/config';
|
||||
import jwtConfig from '@/config/jwt.config';
|
||||
import { LoginProvider } from './login.provider';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
/**
|
||||
* Inject Users Service
|
||||
* Inject Login Provider
|
||||
*/
|
||||
private readonly usersService: UsersService,
|
||||
|
||||
/**
|
||||
* Inject OTP Service
|
||||
*/
|
||||
private readonly otpService: OtpService,
|
||||
|
||||
/**
|
||||
* Inject Hashing Provider
|
||||
*/
|
||||
private readonly hashingProvider: HashingProvider,
|
||||
|
||||
/**
|
||||
* Inject Jwt Service
|
||||
*/
|
||||
private readonly jwtService: JwtService,
|
||||
|
||||
/**
|
||||
* Inject Jwt Config
|
||||
*/
|
||||
@Inject(jwtConfig.KEY)
|
||||
private readonly jwtConfiguration: ConfigType<typeof jwtConfig>,
|
||||
private readonly loginProvider: LoginProvider,
|
||||
) {}
|
||||
|
||||
public async logIn(loginDto: LoginDTO) {
|
||||
const { phone, password } = loginDto;
|
||||
const user = await this.usersService.findOneByPhone(phone);
|
||||
|
||||
if (!user) {
|
||||
// TODO: Send OTP
|
||||
const otpCode = await this.otpService.createOTP(phone);
|
||||
|
||||
return {
|
||||
newUser: true,
|
||||
message: `Otp sent to ${phone}`,
|
||||
// Just for development
|
||||
code: otpCode,
|
||||
};
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
return {
|
||||
newUser: false,
|
||||
message: 'Please send password',
|
||||
};
|
||||
}
|
||||
|
||||
const isPasswordCorrect = await this.hashingProvider.compare(
|
||||
password,
|
||||
user.password || '',
|
||||
);
|
||||
|
||||
if (isPasswordCorrect) {
|
||||
const tokenPayload = {
|
||||
sub: user.id,
|
||||
phone: user.phone,
|
||||
};
|
||||
|
||||
const accessToken = await this.jwtService.signAsync(tokenPayload);
|
||||
|
||||
const refreshToken = await this.jwtService.signAsync(tokenPayload, {
|
||||
secret: this.jwtConfiguration.refresh.secret,
|
||||
expiresIn: this.jwtConfiguration.refresh.expiresIn,
|
||||
});
|
||||
|
||||
return { access: accessToken, refresh: refreshToken };
|
||||
}
|
||||
|
||||
throw new UnauthorizedException(
|
||||
'Entered phone number or password is wrong.',
|
||||
);
|
||||
return await this.loginProvider.logIn(loginDto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import jwtConfig from '@/config/jwt.config';
|
||||
import { User } from '@/modules/users/user.entity';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { ConfigType } from '@nestjs/config';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import {
|
||||
AccessTokenPayload,
|
||||
RefreshTokenPayload,
|
||||
} from '../interfaces/jwt.interface';
|
||||
|
||||
@Injectable()
|
||||
export class GenerateTokenProvider {
|
||||
constructor(
|
||||
/**
|
||||
* Inject Jwt Service
|
||||
*/
|
||||
private readonly jwtService: JwtService,
|
||||
|
||||
/**
|
||||
* Inject Jwt Config
|
||||
*/
|
||||
@Inject(jwtConfig.KEY)
|
||||
private readonly jwtConfiguration: ConfigType<typeof jwtConfig>,
|
||||
) {}
|
||||
|
||||
public async signToken<T>(
|
||||
userId: number,
|
||||
expiresIn: number,
|
||||
secret?: string,
|
||||
payload?: T,
|
||||
) {
|
||||
return await this.jwtService.signAsync(
|
||||
{
|
||||
sub: userId,
|
||||
...payload,
|
||||
},
|
||||
{
|
||||
audience: this.jwtConfiguration.audience,
|
||||
issuer: this.jwtConfiguration.issuer,
|
||||
secret,
|
||||
expiresIn,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public async generateTokens(user: User, jti: string) {
|
||||
const [access, refresh] = await Promise.all([
|
||||
// Sign Access Token
|
||||
this.signToken<Partial<AccessTokenPayload>>(
|
||||
user.id,
|
||||
this.jwtConfiguration.access.expiresIn,
|
||||
this.jwtConfiguration.access.secret,
|
||||
{ phone: user.phone },
|
||||
),
|
||||
|
||||
// Sign Refresh Token
|
||||
this.signToken<Partial<RefreshTokenPayload>>(
|
||||
user.id,
|
||||
this.jwtConfiguration.refresh.expiresIn,
|
||||
this.jwtConfiguration.refresh.secret,
|
||||
{ jti },
|
||||
),
|
||||
]);
|
||||
|
||||
return { access, refresh };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { LoginDTO } from '../dtos/login.dto';
|
||||
import { UsersService } from '@/modules/users/providers/users.service';
|
||||
import { OtpService } from '@/modules/otp/providers/otp.service';
|
||||
import { HashingProvider } from '@/common/modules/hashing/providers/hashing.provider';
|
||||
import { GenerateTokenProvider } from './generate-token.provider';
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
@Injectable()
|
||||
export class LoginProvider {
|
||||
constructor(
|
||||
/**
|
||||
* Inject Users Service
|
||||
*/
|
||||
private readonly usersService: UsersService,
|
||||
|
||||
/**
|
||||
* Inject OTP Service
|
||||
*/
|
||||
private readonly otpService: OtpService,
|
||||
|
||||
/**
|
||||
* Inject Hashing Provider
|
||||
*/
|
||||
private readonly hashingProvider: HashingProvider,
|
||||
|
||||
/**
|
||||
* Inject GenerateToken Provider
|
||||
*/
|
||||
private readonly generateTokenProvider: GenerateTokenProvider,
|
||||
) {}
|
||||
|
||||
public async logIn(loginDto: LoginDTO) {
|
||||
const { phone, password } = loginDto;
|
||||
const user = await this.usersService.findOneByPhone(phone);
|
||||
|
||||
if (!user) {
|
||||
// TODO: Send OTP
|
||||
const otpCode = await this.otpService.createOTP(phone);
|
||||
|
||||
return {
|
||||
newUser: true,
|
||||
message: `Otp sent to ${phone}`,
|
||||
// Just for development
|
||||
code: otpCode,
|
||||
};
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
return {
|
||||
newUser: false,
|
||||
message: 'Please send password',
|
||||
};
|
||||
}
|
||||
|
||||
const isPasswordCorrect = await this.hashingProvider.compare(
|
||||
password,
|
||||
user.password || '',
|
||||
);
|
||||
|
||||
if (isPasswordCorrect) {
|
||||
const jti = randomUUID();
|
||||
return await this.generateTokenProvider.generateTokens(user, jti);
|
||||
}
|
||||
|
||||
throw new UnauthorizedException(
|
||||
'Entered phone number or password is wrong.',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import { Injectable, RequestTimeoutException } from '@nestjs/common';
|
||||
import { Repository } from 'typeorm';
|
||||
import { User } from '../user.entity';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { CreateUserDTO } from '../dto/create-user.dto';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
@@ -25,8 +24,8 @@ export class UsersService {
|
||||
}
|
||||
}
|
||||
|
||||
public async createOne(createUserDto: CreateUserDTO) {
|
||||
const newUser = this.userRepository.create(createUserDto);
|
||||
public async createOne(phone: string) {
|
||||
const newUser = this.userRepository.create({ phone });
|
||||
|
||||
try {
|
||||
await this.userRepository.save(newUser);
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
ParseIntPipe,
|
||||
Post,
|
||||
} from '@nestjs/common';
|
||||
import { CreateUserDTO } from './dto/create-user.dto';
|
||||
import { Controller } from '@nestjs/common';
|
||||
import { UsersService } from './providers/users.service';
|
||||
|
||||
@Controller('users')
|
||||
@@ -18,18 +10,18 @@ export class UsersController {
|
||||
private readonly usersService: UsersService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
public getAllUsers() {
|
||||
return ['user1', 'user2'];
|
||||
}
|
||||
// @Get()
|
||||
// public getAllUsers() {
|
||||
// return ['user1', 'user2'];
|
||||
// }
|
||||
|
||||
@Get(':id')
|
||||
public getUserById(@Param('id', ParseIntPipe) id: number) {
|
||||
return `user ${id}`;
|
||||
}
|
||||
// @Get(':id')
|
||||
// public getUserById(@Param('id', ParseIntPipe) id: number) {
|
||||
// return `user ${id}`;
|
||||
// }
|
||||
|
||||
@Post()
|
||||
public async createUser(@Body() createUserDto: CreateUserDTO) {
|
||||
return await this.usersService.createOne(createUserDto);
|
||||
}
|
||||
// @Post()
|
||||
// public async createUser(@Body() createUserDto: CreateUserDTO) {
|
||||
// return await this.usersService.createOne(createUserDto);
|
||||
// }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user