testing all features

This commit is contained in:
Kevsl
2024-06-06 16:31:31 +02:00
commit 9f5c23c7c9
74 changed files with 18541 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthLoginDto, AuthRegisterDto } from './dto';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('auth')
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@Post('signup')
signup(@Body() dto: AuthRegisterDto) {
return this.authService.signup(dto);
}
@HttpCode(HttpStatus.OK)
@Post('signin')
signin(@Body() dto: AuthLoginDto) {
return this.authService.signin(dto);
}
}

12
src/auth/auth.module.ts Normal file
View File

@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from './strategy';
@Module({
imports: [JwtModule.register({})],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
})
export class AuthModule {}

92
src/auth/auth.service.ts Normal file
View File

@@ -0,0 +1,92 @@
import { ForbiddenException, Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { AuthLoginDto, AuthRegisterDto } from './dto';
import * as argon from 'argon2';
import { Prisma } from '@prisma/client';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class AuthService {
constructor(
private prisma: PrismaService,
private jwt: JwtService,
private config: ConfigService,
) {}
async signup(dto: AuthRegisterDto) {
const hash = await argon.hash(dto.password);
const promoCode = await this.prisma.promoCode.findFirst({
where: {
name: dto.promoCode,
},
});
const userRole = await this.prisma.role.findFirst({
where: {
name: 'user',
},
});
let balance = 1000;
if (promoCode && promoCode.value) {
balance = promoCode.value;
}
try {
const user = await this.prisma.user.create({
data: {
firstName: dto.firstName,
lastName: dto.lastName,
pseudo: dto.pseudo,
city: dto.city,
email: dto.email,
hash,
roleId: userRole.id,
isActive: true,
dollarAvailables: balance,
},
});
return this.signToken(user.id, user.email);
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2002') {
throw new ForbiddenException('Credentials taken');
}
}
throw error;
}
}
async signin(dto: AuthLoginDto) {
const user = await this.prisma.user.findUnique({
where: {
email: dto.email,
},
});
if (!user) throw new ForbiddenException('Credentials incorrect');
const pwMatches = await argon.verify(user.hash, dto.password);
if (!pwMatches) throw new ForbiddenException('Credentials incorrect');
return this.signToken(user.id, user.email);
}
async signToken(
userId: string,
email: string,
): Promise<{ access_token: string }> {
const payload = {
sub: userId,
email: email,
};
const secret = this.config.get('JWT_SECRET');
const token = await this.jwt.signAsync(payload, {
expiresIn: '30d',
secret: secret,
});
return {
access_token: token,
};
}
}

View File

@@ -0,0 +1,11 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const GetUser = createParamDecorator(
(data: string | undefined, ctx: ExecutionContext) => {
const request: Express.Request = ctx.switchToHttp().getRequest();
if (data) {
return request.user[data];
}
return request.user;
},
);

View File

@@ -0,0 +1 @@
export * from './get-user.decorator';

View File

@@ -0,0 +1,13 @@
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class AuthLoginDto {
@IsEmail()
@IsNotEmpty()
@ApiProperty({ type: String, description: 'email' })
email: string;
@ApiProperty({ type: String, description: 'password' })
@IsString()
@IsNotEmpty()
password: string;
}

View File

@@ -0,0 +1,65 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
export class AuthRegisterDto {
@ApiProperty({
type: String,
description: 'FirstName',
example: 'Thomas',
})
@IsNotEmpty()
@IsString()
firstName: string;
@ApiProperty({
type: String,
description: 'Last Name',
example: 'Anderson',
})
@IsNotEmpty()
@IsString()
lastName: string;
@ApiProperty({
type: String,
description: 'Pseudo',
example: 'Néo',
})
@IsNotEmpty()
@IsString()
pseudo: string;
@ApiProperty({
type: String,
description: 'User city',
example: 'Aix les bains',
})
@IsNotEmpty()
@IsString()
city: string;
@ApiProperty({
type: String,
description: 'email',
example: 'neo@matrix.fr',
})
@IsEmail()
@IsNotEmpty()
email: string;
@ApiProperty({
type: String,
description: 'password',
example: 'AAaa11&&&&',
})
@IsString()
@IsNotEmpty()
password: string;
@ApiProperty({
type: String,
description: 'promoCode',
example: 'FILOU20',
})
@IsOptional()
promoCode: string;
}

2
src/auth/dto/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './auth.register.dto';
export * from './auth.login.dto';

1
src/auth/guard/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './jwt.guard';

View File

@@ -0,0 +1,7 @@
import { AuthGuard } from '@nestjs/passport';
export class JwtGuard extends AuthGuard('jwt') {
constructor() {
super();
}
}

View File

@@ -0,0 +1 @@
export * from './jwt.strategy';

View File

@@ -0,0 +1,28 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PrismaService } from '../../prisma/prisma.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor(
config: ConfigService,
private prisma: PrismaService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: config.get('JWT_SECRET'),
});
}
async validate(payload: { sub: string; email: string }) {
const user = await this.prisma.user.findUnique({
where: {
id: payload.sub,
},
});
delete user.hash;
return user;
}
}