diff --git a/backend/src/admin/admin.controller.ts b/backend/src/admin/admin.controller.ts index 2b3cce941a2ab8a557119f894358ff635cd1905b..fd2874a856bb72b7474eb918dd233cb25a0202b5 100644 --- a/backend/src/admin/admin.controller.ts +++ b/backend/src/admin/admin.controller.ts @@ -1,15 +1,6 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Delete, -} from '@nestjs/common'; +import { Controller, Post, Body } from '@nestjs/common'; import { AdminService } from './admin.service'; import { CreateAdminDto } from './dto/create-admin.dto'; -import { UpdateAdminDto } from './dto/update-admin.dto'; @Controller('admin') export class AdminController { @@ -19,24 +10,4 @@ export class AdminController { create(@Body() createAdminDto: CreateAdminDto) { return this.adminService.create(createAdminDto); } - - @Get() - findAll() { - return this.adminService.findAll(); - } - - @Get(':id') - findOne(@Param('id') id: string) { - // return this.adminService.findOne(+id); - } - - @Patch(':id') - update(@Param('id') id: string, @Body() updateAdminDto: UpdateAdminDto) { - return this.adminService.update(+id, updateAdminDto); - } - - @Delete(':id') - remove(@Param('id') id: string) { - return this.adminService.remove(+id); - } } diff --git a/backend/src/admin/admin.service.ts b/backend/src/admin/admin.service.ts index 7c3edb1198bbfb0d185045b05a6f903cde6e190e..ca642dc95b9c474c260f02e44be70bc5e7d8506e 100644 --- a/backend/src/admin/admin.service.ts +++ b/backend/src/admin/admin.service.ts @@ -1,6 +1,5 @@ import { Injectable } from '@nestjs/common'; import { CreateAdminDto } from './dto/create-admin.dto'; -import { UpdateAdminDto } from './dto/update-admin.dto'; import { Admin } from './entities/admin.entity'; import { Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; @@ -14,19 +13,7 @@ export class AdminService { await this.adminRepository.insert(createAdminDto); } - findAll() { - return `This action returns all admin`; - } - async findOne(email: string): Promise { return await this.adminRepository.findOneByOrFail({ email }); } - - update(id: number, updateAdminDto: UpdateAdminDto) { - return `This action updates a #${id} admin`; - } - - remove(id: number) { - return `This action removes a #${id} admin`; - } } diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 2b0ef58132cf5ba237f5885c66c7c78026348bca..4ec2c55f53d6b90629af08cb8fc1289cca6717d1 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -1,13 +1,14 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { DataSource } from 'typeorm'; - import { AppController } from './app.controller'; import { AppService } from './app.service'; import { AdminModule } from './admin/admin.module'; import { Admin } from './admin/entities/admin.entity'; import { DbConstants } from './constants/db.constants'; import { AuthAdminModule } from './auth/admin/authAdmin.module'; +import { UserModule } from './user/user.module'; +import { User } from './user/entities/user.entity'; +import { AuthUserModule } from './auth/user/authUser.module'; @Module({ imports: [ TypeOrmModule.forRoot({ @@ -17,11 +18,13 @@ import { AuthAdminModule } from './auth/admin/authAdmin.module'; username: DbConstants.DB_USER, password: DbConstants.DB_PASSWORD, database: DbConstants.DB_NAME, - entities: [Admin], + entities: [Admin, User], synchronize: DbConstants.DB_SYNC, }), AuthAdminModule, AdminModule, + UserModule, + AuthUserModule, ], controllers: [AppController], providers: [AppService], diff --git a/backend/src/auth/admin/authAdmincontroller.ts b/backend/src/auth/admin/authAdmincontroller.ts index 526f6c8fedd30b5be83dbf3911dc23e4a9d05586..72f0c0a33e47e895a948ba215a5694c26fb35a9e 100644 --- a/backend/src/auth/admin/authAdmincontroller.ts +++ b/backend/src/auth/admin/authAdmincontroller.ts @@ -3,7 +3,6 @@ import { AuthAdminService } from './authAdminservice'; import { CreateAdminDto } from 'src/admin/dto/create-admin.dto'; import { LoginAdminDto } from 'src/auth/admin/dto/login-admin.dto'; import { - ApiBearerAuth, ApiBody, ApiCreatedResponse, ApiTags, @@ -11,13 +10,12 @@ import { } from '@nestjs/swagger'; import { AdminSigninResDto } from './dto/admin-signin-res.dto'; -@Controller('auth') +@Controller() @ApiTags('Create admin account and sign in as admin') export class AuthAdminController { constructor(private readonly authAdminService: AuthAdminService) {} @ApiBody({ type: CreateAdminDto }) - @ApiBearerAuth() @ApiCreatedResponse({ content: { 'application/json': { @@ -34,7 +32,7 @@ export class AuthAdminController { const accessToken = await this.authAdminService.signUp(createAdminDto); return { token: accessToken }; } catch (e) { - throw e; + return e; } } @ApiBody({ type: LoginAdminDto }) diff --git a/backend/src/auth/user/authUser.module.ts b/backend/src/auth/user/authUser.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..22ac1b095f28932baa63f08b6b2b57b6c2370453 --- /dev/null +++ b/backend/src/auth/user/authUser.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { EncryptionService } from '../encryption/encryption.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { JwtService } from '@nestjs/jwt'; +import { AuthUserController } from './authUsercontroller'; +import { UserService } from 'src/user/user.service'; +import { User } from 'src/user/entities/user.entity'; +import { AuthUserService } from './authUserservice'; +@Module({ + controllers: [AuthUserController], + providers: [UserService, JwtService, EncryptionService, AuthUserService], + imports: [TypeOrmModule.forFeature([User])], +}) +export class AuthUserModule {} diff --git a/backend/src/auth/user/authUsercontroller.ts b/backend/src/auth/user/authUsercontroller.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd4bd9aaf989ace1ce269e4df45c4efed3196ed0 --- /dev/null +++ b/backend/src/auth/user/authUsercontroller.ts @@ -0,0 +1,50 @@ +import { Body, Controller, Post } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiBody, + ApiCreatedResponse, + ApiTags, + ApiUnauthorizedResponse, +} from '@nestjs/swagger'; +import { AuthUserService } from './authUserservice'; +import { CreateUserDto } from 'src/user/dto/create-user.dto'; +import { LoginUserDto } from './dto/login-user.dto'; + +@Controller('') +@ApiTags('Create user account and sign in as user') +export class AuthUserController { + constructor(private readonly authUserService: AuthUserService) {} + + @ApiBody({ type: CreateUserDto }) + @ApiBearerAuth() + @ApiCreatedResponse({ + content: { + 'application/json': { + example: { + token: 'token', + }, + }, + }, + }) + @Post('user/signup') + async signUp(@Body() createAdminDto: CreateUserDto) { + try { + const accessToken = await this.authUserService.signUp(createAdminDto); + return { token: accessToken }; + } catch (e) { + throw e; + } + } + @ApiBody({ type: LoginUserDto }) + @ApiUnauthorizedResponse() + @Post('user/signin') + async signIn(@Body() loginAdminDto: LoginUserDto) { + try { + const adminSigninResDto = + await this.authUserService.signIn(loginAdminDto); + return adminSigninResDto; + } catch (e) { + throw e; + } + } +} diff --git a/backend/src/auth/user/authUserservice.ts b/backend/src/auth/user/authUserservice.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9cf9d7b98fba1b14c1b5b1438819180ac5845e1 --- /dev/null +++ b/backend/src/auth/user/authUserservice.ts @@ -0,0 +1,56 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { EncryptionService } from '../encryption/encryption.service'; +import { JwtConstants } from 'src/constants/jwt.constants'; +import { UserSigninResDto } from './dto/user-signin-res.dto'; +import { User } from 'src/user/entities/user.entity'; +import { UserService } from 'src/user/user.service'; +import { CreateUserDto } from 'src/user/dto/create-user.dto'; +import { LoginUserDto } from './dto/login-user.dto'; + +@Injectable() +export class AuthUserService { + constructor( + private userService: UserService, + private jwtService: JwtService, + private encryptionService: EncryptionService, + ) {} + + async signUp(createAdminDto: CreateUserDto): Promise { + const loginAdminDto: LoginUserDto = { + email: createAdminDto.email, + password: createAdminDto.password, + }; + const hashedPwd = await this.encryptionService.hashPassword( + createAdminDto.password, + ); + createAdminDto.password = hashedPwd; + await this.userService.create(createAdminDto); + + const adminSigninResDto: UserSigninResDto = + await this.signIn(loginAdminDto); + return adminSigninResDto.token; + } + + async signIn(logInAdmin: LoginUserDto): Promise { + const user: User = await this.userService.findOne(logInAdmin.email); + const validPwd: boolean = await this.encryptionService.comparePassword( + logInAdmin.password, + user.password, + ); + if (!validPwd) { + throw new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED); + } + const accessToken = await this.jwtService.sign( + { email: user.email, name: user.name, lastName: user.lastName }, + { secret: JwtConstants.SECRET }, + ); + const userSigninResDto: UserSigninResDto = { + email: user.email, + name: user.name, + lastName: user.lastName, + token: accessToken, + }; + return userSigninResDto; + } +} diff --git a/backend/src/auth/user/dto/login-user.dto.ts b/backend/src/auth/user/dto/login-user.dto.ts new file mode 100644 index 0000000000000000000000000000000000000000..e9fec99c51ec861fb4da076aa6f29921415863c5 --- /dev/null +++ b/backend/src/auth/user/dto/login-user.dto.ts @@ -0,0 +1,8 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class LoginUserDto { + @ApiProperty() + email: string; + @ApiProperty() + password: string; +} diff --git a/backend/src/auth/user/dto/user-signin-res.dto.ts b/backend/src/auth/user/dto/user-signin-res.dto.ts new file mode 100644 index 0000000000000000000000000000000000000000..4491c55b0bd078e90126193a898d78882909aee4 --- /dev/null +++ b/backend/src/auth/user/dto/user-signin-res.dto.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class UserSigninResDto { + @ApiProperty() + email: string; + @ApiProperty() + name: string; + @ApiProperty() + lastName: string; + @ApiProperty() + token: string; +} diff --git a/backend/src/user/dto/create-user.dto.ts b/backend/src/user/dto/create-user.dto.ts new file mode 100644 index 0000000000000000000000000000000000000000..89a565be2bb815d380df0e69d9f3c6b8c60680eb --- /dev/null +++ b/backend/src/user/dto/create-user.dto.ts @@ -0,0 +1,14 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateUserDto { + @ApiProperty() + email: string; + @ApiProperty() + name: string; + @ApiProperty() + lastName: string; + @ApiProperty() + password: string; + @ApiProperty() + birthdate: Date; +} diff --git a/backend/src/user/dto/update-user.dto.ts b/backend/src/user/dto/update-user.dto.ts new file mode 100644 index 0000000000000000000000000000000000000000..78ab602d8ddf6fc7606a9b6abf736549d9e8630d --- /dev/null +++ b/backend/src/user/dto/update-user.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateUserDto } from './create-user.dto'; + +export class UpdateUserDto extends PartialType(CreateUserDto) {} diff --git a/backend/src/user/entities/user.entity.ts b/backend/src/user/entities/user.entity.ts new file mode 100644 index 0000000000000000000000000000000000000000..960373866c3af1efcc74beea36223052a0cdd00e --- /dev/null +++ b/backend/src/user/entities/user.entity.ts @@ -0,0 +1,24 @@ +import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; + +@Entity() +export class User { + @PrimaryGeneratedColumn() + id: number; + + @Column({ + unique: true, + }) + email: string; + + @Column() + name: string; + + @Column() + lastName: string; + + @Column() + birthDate: Date; + + @Column() + password: string; +} diff --git a/backend/src/user/user.controller.ts b/backend/src/user/user.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac921025eee12e482ff0e9fffbb2102e9ad70598 --- /dev/null +++ b/backend/src/user/user.controller.ts @@ -0,0 +1,17 @@ +import { Controller, Post, Body } from '@nestjs/common'; +import { UserService } from './user.service'; +import { CreateUserDto } from './dto/create-user.dto'; + +@Controller('user') +export class UserController { + constructor(private readonly userService: UserService) {} + + @Post() + create(@Body() createUserDto: CreateUserDto) { + try { + return this.userService.create(createUserDto); + } catch (error) { + return error; + } + } +} diff --git a/backend/src/user/user.module.ts b/backend/src/user/user.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a4003a16a1c30277f38833fab0bae0eb9e7313d --- /dev/null +++ b/backend/src/user/user.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { UserService } from './user.service'; +import { UserController } from './user.controller'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { User } from './entities/user.entity'; + +@Module({ + controllers: [UserController], + providers: [UserService], + imports: [TypeOrmModule.forFeature([User])], +}) +export class UserModule {} diff --git a/backend/src/user/user.service.ts b/backend/src/user/user.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f17c0029e8658c024bc00a287c5f009732e3537 --- /dev/null +++ b/backend/src/user/user.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { User } from './entities/user.entity'; +import { Repository } from 'typeorm'; +import { CreateUserDto } from './dto/create-user.dto'; + +@Injectable() +/** + * Service responsible for handling user-related operations. + */ +export class UserService { + constructor( + @InjectRepository(User) private userRepository: Repository, + ) {} + + async findOne(email: string) { + return await this.userRepository.findOneByOrFail({ email }); + } + + async create(createUserDto: CreateUserDto) { + await this.userRepository.insert(createUserDto); + } +}