From 32b3c6558c9630806a8c98b844098b2f25b745ef Mon Sep 17 00:00:00 2001 From: gabito1451 Date: Wed, 22 Apr 2026 09:30:23 -0700 Subject: [PATCH 1/2] Implemented User Registration: Added firstName and lastName to the User model, implemented comprehensive email and password strength validation, ensured email uniqueness, and updated the API to return sanitized user data. --- src/app.module.ts | 2 ++ src/auth/auth.controller.ts | 14 +++++++++++ src/auth/auth.module.ts | 12 ++++++++++ src/auth/auth.service.ts | 45 ++++++++++++++++++++++++++++++++++++ src/auth/dto/register.dto.ts | 26 +++++++++++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 src/auth/auth.controller.ts create mode 100644 src/auth/auth.module.ts create mode 100644 src/auth/auth.service.ts create mode 100644 src/auth/dto/register.dto.ts diff --git a/src/app.module.ts b/src/app.module.ts index d4ff518e..d59995ce 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { UsersModule } from './users/users.module'; +import { AuthModule } from './auth/auth.module'; import { PropertiesModule } from './properties/properties.module'; import { PrismaModule } from './database/prisma.module'; import { AppController } from './app.controller'; @@ -13,6 +14,7 @@ import { AppController } from './app.controller'; }), PrismaModule, UsersModule, + AuthModule, PropertiesModule, ], controllers: [AppController], diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts new file mode 100644 index 00000000..e1108518 --- /dev/null +++ b/src/auth/auth.controller.ts @@ -0,0 +1,14 @@ +import { Controller, Post, Body, HttpCode, HttpStatus } from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { RegisterDto } from './dto/register.dto'; + +@Controller('auth') +export class AuthController { + constructor(private authService: AuthService) {} + + @Post('register') + @HttpCode(HttpStatus.CREATED) + async register(@Body() registerDto: RegisterDto) { + return this.authService.register(registerDto); + } +} diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts new file mode 100644 index 00000000..e48dbec0 --- /dev/null +++ b/src/auth/auth.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { AuthController } from './auth.controller'; +import { UsersModule } from '../users/users.module'; + +@Module({ + imports: [UsersModule], + providers: [AuthService], + controllers: [AuthController], + exports: [AuthService], +}) +export class AuthModule {} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts new file mode 100644 index 00000000..a62f1fb3 --- /dev/null +++ b/src/auth/auth.service.ts @@ -0,0 +1,45 @@ +import { Injectable, ConflictException, InternalServerErrorException } from '@nestjs/common'; +import { UsersService } from '../users/users.service'; +import { RegisterDto } from './dto/register.dto'; +import * as bcrypt from 'bcrypt'; + +@Injectable() +export class AuthService { + constructor(private usersService: UsersService) {} + + async register(registerDto: RegisterDto) { + const { email, password, firstName, lastName, phone } = registerDto; + + // Check if user already exists + const existingUser = await this.usersService.findByEmail(email); + if (existingUser) { + throw new ConflictException('Email already exists'); + } + + try { + // Hash password + const salt = await bcrypt.genSalt(); + const hashedPassword = await bcrypt.hash(password, salt); + + // Create user + const user = await this.usersService.create({ + email, + password: hashedPassword, + firstName, + lastName, + phone, + }); + + return { + message: 'Registration successful', + user, + }; + } catch (error) { + if (error.code === '23505') { + // Unique constraint violation (though we check it above, this is for safety) + throw new ConflictException('Email already exists'); + } + throw new InternalServerErrorException('Error registering user'); + } + } +} diff --git a/src/auth/dto/register.dto.ts b/src/auth/dto/register.dto.ts new file mode 100644 index 00000000..e9908ebe --- /dev/null +++ b/src/auth/dto/register.dto.ts @@ -0,0 +1,26 @@ +import { IsEmail, IsNotEmpty, IsString, MinLength, Matches } from 'class-validator'; + +export class RegisterDto { + @IsEmail({}, { message: 'Please provide a valid email address' }) + @IsNotEmpty({ message: 'Email is required' }) + email: string; + + @IsString() + @MinLength(8, { message: 'Password must be at least 8 characters long' }) + @Matches(/((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, { + message: 'Password is too weak. It must contain at least one uppercase letter, one lowercase letter, and at least one number or special character.', + }) + password: string; + + @IsString() + @IsNotEmpty({ message: 'First name is required' }) + firstName: string; + + @IsString() + @IsNotEmpty({ message: 'Last name is required' }) + lastName: string; + + @IsString() + @IsNotEmpty({ message: 'Phone number is required' }) + phone: string; +} From a195b68ef0c6e1c4a906e824661530fdf9eb2eb7 Mon Sep 17 00:00:00 2001 From: gabito1451 Date: Wed, 22 Apr 2026 09:36:54 -0700 Subject: [PATCH 2/2] fix --- src/app.module.ts | 2 -- src/auth/dto/auth.dto.ts | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index a2303de8..d59995ce 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,7 +5,6 @@ import { AuthModule } from './auth/auth.module'; import { PropertiesModule } from './properties/properties.module'; import { PrismaModule } from './database/prisma.module'; import { AppController } from './app.controller'; -import { AuthModule } from './auth/auth.module'; @Module({ imports: [ @@ -17,7 +16,6 @@ import { AuthModule } from './auth/auth.module'; UsersModule, AuthModule, PropertiesModule, - AuthModule, ], controllers: [AppController], }) diff --git a/src/auth/dto/auth.dto.ts b/src/auth/dto/auth.dto.ts index 584e90ef..8b7b2ed2 100644 --- a/src/auth/dto/auth.dto.ts +++ b/src/auth/dto/auth.dto.ts @@ -5,6 +5,7 @@ import { IsOptional, IsString, MinLength, + Matches, } from 'class-validator'; export class RegisterDto { @@ -12,7 +13,10 @@ export class RegisterDto { email: string; @IsString() - @MinLength(8) + @MinLength(8, { message: 'Password must be at least 8 characters long' }) + @Matches(/((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, { + message: 'Password is too weak. It must contain at least one uppercase letter, one lowercase letter, and at least one number or special character.', + }) password: string; @IsString()