auth implemented
This commit is contained in:
parent
ce501e6450
commit
96e8628dad
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/home/echo/dev/nestjs_boilerplate/server/node_modules
|
||||
/server/node_modules
|
||||
/server/dist
|
||||
|
||||
3
server/.gitignore
vendored
Normal file
3
server/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
# Keep environment variables out of version control
|
||||
.env
|
||||
922
server/package-lock.json
generated
922
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -21,8 +21,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.3.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/jwt": "^10.2.0",
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@prisma/client": "^6.0.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^8.13.1",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
@ -30,9 +41,12 @@
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/passport-jwt": "^4.0.1",
|
||||
"@types/passport-local": "^1.0.38",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
@ -41,6 +55,7 @@
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
"prisma": "^6.0.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
|
||||
19
server/prisma/migrations/20241209005623_init/migration.sql
Normal file
19
server/prisma/migrations/20241209005623_init/migration.sql
Normal file
@ -0,0 +1,19 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Role" AS ENUM ('USER', 'ADMIN');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "users" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"firstName" TEXT,
|
||||
"lastName" TEXT,
|
||||
"role" "Role" NOT NULL DEFAULT 'USER',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
||||
@ -0,0 +1,9 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `firstName` on the `users` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" DROP COLUMN "firstName",
|
||||
ADD COLUMN "name" TEXT;
|
||||
3
server/prisma/migrations/migration_lock.toml
Normal file
3
server/prisma/migrations/migration_lock.toml
Normal file
@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
32
server/prisma/schema.prisma
Normal file
32
server/prisma/schema.prisma
Normal file
@ -0,0 +1,32 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
email String @unique
|
||||
password String
|
||||
name String?
|
||||
lastName String?
|
||||
role Role @default(USER)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
enum Role {
|
||||
USER
|
||||
ADMIN
|
||||
}
|
||||
@ -1,10 +1,24 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { jwtConfig } from './config/configuration';
|
||||
import { AuthModule } from './modules/auth/auth.module';
|
||||
import { PrismaService } from './prisma/prisma.service';
|
||||
import { PrismaModule } from './prisma/prisma.module';
|
||||
import { UsersModule } from './modules/users/users.module';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [jwtConfig],
|
||||
}),
|
||||
AuthModule,
|
||||
PrismaModule,
|
||||
UsersModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
providers: [AppService, PrismaService],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@ -3,6 +3,6 @@ import { Injectable } from '@nestjs/common';
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
getHello(): string {
|
||||
return 'Hello World!';
|
||||
return 'up and running ';
|
||||
}
|
||||
}
|
||||
|
||||
4
server/src/common/enums/role.enum.ts
Normal file
4
server/src/common/enums/role.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum Role {
|
||||
USER = 'USER',
|
||||
ADMIN = 'ADMIN',
|
||||
}
|
||||
8
server/src/config/configuration.ts
Normal file
8
server/src/config/configuration.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export const jwtConfig = registerAs('jwt', () => ({
|
||||
secret: process.env.JWT_SECRET || 'secret',
|
||||
expiresIn: process.env.JWT_EXPIRES_IN || '1d',
|
||||
}));
|
||||
|
||||
export const PORT = process.env.PORT || 3000;
|
||||
33
server/src/core/filters/http-exception.filters.ts
Normal file
33
server/src/core/filters/http-exception.filters.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import {
|
||||
ExceptionFilter,
|
||||
Catch,
|
||||
ArgumentsHost,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
|
||||
@Catch()
|
||||
export class GlobalExceptionFilter implements ExceptionFilter {
|
||||
catch(exception: unknown, host: ArgumentsHost) {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse();
|
||||
const request = ctx.getRequest();
|
||||
|
||||
const status =
|
||||
exception instanceof HttpException
|
||||
? exception.getStatus()
|
||||
: HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
const message =
|
||||
exception instanceof HttpException
|
||||
? exception.getResponse()
|
||||
: 'Internal server error';
|
||||
|
||||
response.status(status).json({
|
||||
statusCode: status,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
message,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,22 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { GlobalExceptionFilter } from './core/filters/http-exception.filters';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
app.setGlobalPrefix('api');
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
whitelist: true,
|
||||
transform: true,
|
||||
}),
|
||||
);
|
||||
app.useGlobalFilters(new GlobalExceptionFilter());
|
||||
app.enableCors();
|
||||
|
||||
const configService = app.get(ConfigService);
|
||||
await app.listen(configService.get('PORT') || 3000);
|
||||
}
|
||||
bootstrap();
|
||||
|
||||
18
server/src/modules/auth/auth.controller.spec.ts
Normal file
18
server/src/modules/auth/auth.controller.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthController } from './auth.controller';
|
||||
|
||||
describe('AuthController', () => {
|
||||
let controller: AuthController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AuthController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<AuthController>(AuthController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
19
server/src/modules/auth/auth.controller.ts
Normal file
19
server/src/modules/auth/auth.controller.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Controller, Post, Body } from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
@Post('register')
|
||||
async register(@Body() registerDto: RegisterDto) {
|
||||
return this.authService.register(registerDto);
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
async login(@Body() loginDto: LoginDto) {
|
||||
return this.authService.login(loginDto);
|
||||
}
|
||||
}
|
||||
27
server/src/modules/auth/auth.module.ts
Normal file
27
server/src/modules/auth/auth.module.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { AuthService } from './auth.service';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { UsersModule } from '../users/users.module';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
// import { LocalStrategy } from './local.strategy';
|
||||
import { JwtStrategy } from './strategies/jwt.strategy';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
UsersModule,
|
||||
PassportModule.register({ defaultStrategy: 'jwt' }),
|
||||
JwtModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
secret: configService.get('jwt.secret'),
|
||||
signOptions: { expiresIn: configService.get('jwt.expiresIn') },
|
||||
}),
|
||||
inject: [ConfigService],
|
||||
}),
|
||||
],
|
||||
providers: [AuthService, JwtStrategy],
|
||||
controllers: [AuthController],
|
||||
})
|
||||
export class AuthModule {}
|
||||
18
server/src/modules/auth/auth.service.spec.ts
Normal file
18
server/src/modules/auth/auth.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
describe('AuthService', () => {
|
||||
let service: AuthService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AuthService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<AuthService>(AuthService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
59
server/src/modules/auth/auth.service.ts
Normal file
59
server/src/modules/auth/auth.service.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import {
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
ConflictException,
|
||||
} from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
import { CreateUserDto } from '../users/dtos/create-user.dto';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly usersService: UsersService,
|
||||
) {}
|
||||
|
||||
async register(createUserDto: CreateUserDto) {
|
||||
// Check if user already exists
|
||||
const existingUser = await this.usersService.findByEmail(
|
||||
createUserDto.email,
|
||||
);
|
||||
if (existingUser) {
|
||||
throw new ConflictException('User already exists');
|
||||
}
|
||||
|
||||
// Create new user
|
||||
const user = await this.usersService.createUser(createUserDto);
|
||||
|
||||
// Generate JWT token
|
||||
const payload = { email: user.email, sub: user.id, role: user.role };
|
||||
|
||||
return {
|
||||
user,
|
||||
access_token: this.jwtService.sign(payload),
|
||||
};
|
||||
}
|
||||
|
||||
async validateUser(email: string, password: string) {
|
||||
const user = await this.usersService.findByEmail(email);
|
||||
if (!user) {
|
||||
throw new UnauthorizedException('Invalid email or password');
|
||||
}
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
if (!isPasswordValid) {
|
||||
throw new UnauthorizedException('Invalid email or password');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
async login(loginDto: LoginDto) {
|
||||
const payload = { email: loginDto.email, password: loginDto.password };
|
||||
return {
|
||||
access_token: this.jwtService.sign(payload),
|
||||
};
|
||||
}
|
||||
}
|
||||
5
server/src/modules/auth/decorators/roles.decorator.ts
Normal file
5
server/src/modules/auth/decorators/roles.decorator.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { SetMetadata } from '@nestjs/common';
|
||||
import { Role } from '../../../common/enums/role.enum';
|
||||
|
||||
export const ROLES_KEY = 'roles';
|
||||
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
|
||||
11
server/src/modules/auth/dto/login.dto.ts
Normal file
11
server/src/modules/auth/dto/login.dto.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { IsString, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class LoginDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
password: string;
|
||||
}
|
||||
18
server/src/modules/auth/dto/register.dto.ts
Normal file
18
server/src/modules/auth/dto/register.dto.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator';
|
||||
|
||||
export class RegisterDto {
|
||||
@IsEmail()
|
||||
email: string;
|
||||
|
||||
@IsString()
|
||||
@MinLength(6)
|
||||
password: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
name?: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
lastName?: string;
|
||||
}
|
||||
5
server/src/modules/auth/guards/jwt-auth.guard.ts
Normal file
5
server/src/modules/auth/guards/jwt-auth.guard.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
||||
20
server/src/modules/auth/guards/roles.guard.ts
Normal file
20
server/src/modules/auth/guards/roles.guard.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Role } from '../../../common/enums/role.enum';
|
||||
|
||||
@Injectable()
|
||||
export class RolesGuard implements CanActivate {
|
||||
constructor(private reflector: Reflector) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const requiredRoles = this.reflector.getAllAndOverride<Role[]>('roles', [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (!requiredRoles) {
|
||||
return true;
|
||||
}
|
||||
const { user } = context.switchToHttp().getRequest();
|
||||
return requiredRoles.some((role) => user.role === role);
|
||||
}
|
||||
}
|
||||
19
server/src/modules/auth/strategies/jwt.strategy.ts
Normal file
19
server/src/modules/auth/strategies/jwt.strategy.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
constructor(private configService: ConfigService) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: configService.get('JWT_SECRET'),
|
||||
});
|
||||
}
|
||||
|
||||
async validate(payload: any) {
|
||||
return { id: payload.sub, email: payload.email, role: payload.role };
|
||||
}
|
||||
}
|
||||
30
server/src/modules/users/dtos/create-user.dto.ts
Normal file
30
server/src/modules/users/dtos/create-user.dto.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import {
|
||||
IsEmail,
|
||||
IsString,
|
||||
MinLength,
|
||||
IsOptional,
|
||||
IsEnum,
|
||||
} from 'class-validator';
|
||||
import { Role } from 'src/common/enums/role.enum';
|
||||
|
||||
export class CreateUserDto {
|
||||
@IsString()
|
||||
@IsEmail()
|
||||
email: string;
|
||||
|
||||
@IsString()
|
||||
@MinLength(6)
|
||||
password: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
name?: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
lastName?: string;
|
||||
|
||||
@IsEnum(Role)
|
||||
@IsOptional()
|
||||
role?: Role;
|
||||
}
|
||||
1
server/src/modules/users/dtos/update-user.dto.ts
Normal file
1
server/src/modules/users/dtos/update-user.dto.ts
Normal file
@ -0,0 +1 @@
|
||||
export const UpdateUserDto = class UpdateUserDto {};
|
||||
18
server/src/modules/users/users.controller.spec.ts
Normal file
18
server/src/modules/users/users.controller.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersController } from './users.controller';
|
||||
|
||||
describe('UsersController', () => {
|
||||
let controller: UsersController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [UsersController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<UsersController>(UsersController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
56
server/src/modules/users/users.controller.ts
Normal file
56
server/src/modules/users/users.controller.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Param,
|
||||
UseGuards,
|
||||
Delete,
|
||||
Patch,
|
||||
} from '@nestjs/common';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { RolesGuard } from '../auth/guards/roles.guard';
|
||||
import { Roles } from '../auth/decorators/roles.decorator';
|
||||
import { Role } from '../../common/enums/role.enum';
|
||||
import { UsersService } from './users.service';
|
||||
import { CreateUserDto } from './dtos/create-user.dto';
|
||||
// import { UpdateUserDto } from './dtos/update-user.dto';
|
||||
|
||||
@Controller('users')
|
||||
// @UseGuards(JwtAuthGuard, RolesGuard)
|
||||
export class UsersController {
|
||||
constructor(private readonly usersService: UsersService) {}
|
||||
|
||||
@Post()
|
||||
@Roles(Role.ADMIN) // Only admin can create users through this endpoint
|
||||
create(@Body() createUserDto: CreateUserDto) {
|
||||
return this.usersService.createUser(createUserDto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
// @Roles(Role.ADMIN)
|
||||
findAll() {
|
||||
return this.usersService.findAll();
|
||||
}
|
||||
@Get()
|
||||
findByEmail(email: string) {
|
||||
return this.usersService.findByEmail(email);
|
||||
}
|
||||
// @Get(':id')
|
||||
// @Roles(Role.ADMIN)
|
||||
// findOne(@Param('id') id: string) {
|
||||
// return this.usersService.findById(id);
|
||||
// }
|
||||
|
||||
// @Patch(':id')
|
||||
// @Roles(Role.ADMIN)
|
||||
// update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
||||
// return this.usersService.update(id, updateUserDto);
|
||||
// }
|
||||
|
||||
// @Delete(':id')
|
||||
// @Roles(Role.ADMIN)
|
||||
// remove(@Param('id') id: string) {
|
||||
// return this.usersService.remove(id);
|
||||
// }
|
||||
}
|
||||
10
server/src/modules/users/users.module.ts
Normal file
10
server/src/modules/users/users.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersController } from './users.controller';
|
||||
|
||||
@Module({
|
||||
providers: [UsersService],
|
||||
exports: [UsersService],
|
||||
controllers: [UsersController],
|
||||
})
|
||||
export class UsersModule {}
|
||||
18
server/src/modules/users/users.service.spec.ts
Normal file
18
server/src/modules/users/users.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
describe('UsersService', () => {
|
||||
let service: UsersService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [UsersService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<UsersService>(UsersService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
41
server/src/modules/users/users.service.ts
Normal file
41
server/src/modules/users/users.service.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
// import { User, Prisma } from '@prisma/client';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { CreateUserDto } from './dtos/create-user.dto';
|
||||
import { Role } from 'src/common/enums/role.enum';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
async createUser(createUserDto: CreateUserDto) {
|
||||
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
|
||||
console.log(hashedPassword);
|
||||
const user = await this.prisma.user.create({
|
||||
data: {
|
||||
...createUserDto,
|
||||
password: hashedPassword,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
lastName: true,
|
||||
role: true,
|
||||
},
|
||||
});
|
||||
console.log(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
async findByEmail(email: string) {
|
||||
return this.prisma.user.findUnique({
|
||||
where: { email },
|
||||
});
|
||||
}
|
||||
|
||||
async findAll() {
|
||||
return this.prisma.user.findMany();
|
||||
}
|
||||
}
|
||||
9
server/src/prisma/prisma.module.ts
Normal file
9
server/src/prisma/prisma.module.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { PrismaService } from './prisma.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [PrismaService],
|
||||
exports: [PrismaService],
|
||||
})
|
||||
export class PrismaModule {}
|
||||
18
server/src/prisma/prisma.service.spec.ts
Normal file
18
server/src/prisma/prisma.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { PrismaService } from './prisma.service';
|
||||
|
||||
describe('PrismaService', () => {
|
||||
let service: PrismaService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [PrismaService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<PrismaService>(PrismaService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
16
server/src/prisma/prisma.service.ts
Normal file
16
server/src/prisma/prisma.service.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
@Injectable()
|
||||
export class PrismaService
|
||||
extends PrismaClient
|
||||
implements OnModuleInit, OnModuleDestroy
|
||||
{
|
||||
async onModuleInit() {
|
||||
await this.$connect();
|
||||
}
|
||||
|
||||
async onModuleDestroy() {
|
||||
await this.$disconnect();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user