From 843c29bd273eb73b4b691addb18c758cbed86fa7 Mon Sep 17 00:00:00 2001 From: thisme8 Date: Thu, 16 Oct 2025 06:17:43 +0545 Subject: [PATCH 1/2] Create User signup with basic CRUD --- src/migrations/1760485409896-users.ts | 2 +- src/user/dto/register-user.dto.ts | 37 ++++++++++++++ src/user/dto/update-user.dto.ts | 32 ++++++++++++ src/user/hash.service.ts | 16 ++++++ src/user/user.controller.ts | 25 ++++++++++ src/user/user.module.ts | 3 +- src/user/user.service.ts | 71 ++++++++++++++++++++++++++- 7 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 src/user/dto/register-user.dto.ts create mode 100644 src/user/dto/update-user.dto.ts create mode 100644 src/user/hash.service.ts diff --git a/src/migrations/1760485409896-users.ts b/src/migrations/1760485409896-users.ts index 7c4112c..4e0386d 100644 --- a/src/migrations/1760485409896-users.ts +++ b/src/migrations/1760485409896-users.ts @@ -3,7 +3,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm'; export class Users1760485409896 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( - `CREATE TABLE "users" ( + `CREATE TABLE IF NOT EXISTS "users" ( "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(), "name" VARCHAR(255) NOT NULL, "username" VARCHAR(255) UNIQUE NOT NULL, diff --git a/src/user/dto/register-user.dto.ts b/src/user/dto/register-user.dto.ts new file mode 100644 index 0000000..d7c316d --- /dev/null +++ b/src/user/dto/register-user.dto.ts @@ -0,0 +1,37 @@ +import { + IsEmail, + IsNotEmpty, + IsString, + Length, + Matches, + MaxLength, + MinLength, +} from 'class-validator'; + +export class RegisterUserDto { + @IsString() + @IsNotEmpty({ message: 'Name is required' }) + @MinLength(2, { message: 'Name must be at least 2 characters' }) + @MaxLength(50, { message: 'Name cannot exceed 50 characters' }) + name: string; + + @IsString() + @IsNotEmpty({ message: 'Username is required' }) + @MinLength(3, { message: 'Username must be at least 3 characters' }) + @MaxLength(20, { message: 'Username cannot exceed 20 characters' }) + @Matches(/^[a-zA-Z0-9_]+$/, { + message: 'Username can only contain letters, numbers, and underscores', + }) + username: string; + + @IsEmail({}, { message: 'Email must be valid' }) + @IsNotEmpty({ message: 'Email is required' }) + @MaxLength(100, { message: 'Email cannot exceed 100 characters' }) + email: string; + + @IsString() + @IsNotEmpty({ message: 'Password is required' }) + @MinLength(6, { message: 'Password must be at least 6 characters' }) + @MaxLength(50, { message: 'Password cannot exceed 50 characters' }) + password: string; +} diff --git a/src/user/dto/update-user.dto.ts b/src/user/dto/update-user.dto.ts new file mode 100644 index 0000000..a8dd988 --- /dev/null +++ b/src/user/dto/update-user.dto.ts @@ -0,0 +1,32 @@ +import { + IsEmail, + IsOptional, + IsString, + Length, + Matches, + MaxLength, + MinLength, +} from 'class-validator'; + +export class UpdateUserDto { + @IsOptional() + @IsString() + @MinLength(2, { message: 'Name must be at least 2 characters' }) + @MaxLength(50, { message: 'Name cannot exceed 50 characters' }) + name?: string; + + @IsOptional() + @IsString() + @MinLength(3, { message: 'Username must be at least 3 characters' }) + @MaxLength(20, { message: 'Username cannot exceed 20 characters' }) + @Matches(/^[a-zA-Z0-9_]+$/, { + message: 'Username can only contain letters, numbers, and underscores', + }) + username?: string; + + @IsOptional() + @IsEmail({}, { message: 'Email must be valid' }) + @MaxLength(100, { message: 'Email cannot exceed 100 characters' }) + email?: string; + +} diff --git a/src/user/hash.service.ts b/src/user/hash.service.ts new file mode 100644 index 0000000..abd94e7 --- /dev/null +++ b/src/user/hash.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@nestjs/common'; +import { randomBytes, scrypt as _scrypt } from 'crypto'; +import { promisify } from 'util'; + +const scrypt = promisify(_scrypt); + +@Injectable() +export class HashService { + private readonly SALT_LENGTH = 16; + + async hashPassword(password: string): Promise { + const salt = randomBytes(this.SALT_LENGTH).toString('hex'); + const hash = (await scrypt(password, salt, 32)) as Buffer; + return `${salt}.${hash.toString('hex')}`; + } +} diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index 2dd6f06..bcd2e36 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -1,7 +1,32 @@ import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; import { UserService } from './user.service'; +import { RegisterUserDto } from './dto/register-user.dto'; +import { UpdateUserDto } from './dto/update-user.dto'; @Controller('users') export class UserController { constructor(private readonly usersService: UserService) {} + + @Post('signup') + async create(@Body() createUserDto: RegisterUserDto) { + const user = await this.usersService.create(createUserDto); + return { message: 'User registered successfully. Please verify your email.', user }; + } + + @Get('get') + async getAllUsers() { + return this.usersService.getAllUsers(); + } + + @Patch(':id') + async update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { + return this.usersService.update(id, updateUserDto); + } + + @Delete(':id') + async remove(@Param('id') id: string) { + return this.usersService.remove(id); + } } + + diff --git a/src/user/user.module.ts b/src/user/user.module.ts index 3b66dc9..53a3d98 100644 --- a/src/user/user.module.ts +++ b/src/user/user.module.ts @@ -3,10 +3,11 @@ import { User } from './entities/user.entity'; import { TypeOrmModule } from '@nestjs/typeorm'; import { UserController } from './user.controller'; import { UserService } from './user.service'; +import { HashService } from './hash.service'; @Module({ imports: [TypeOrmModule.forFeature([User])], controllers: [UserController], - providers: [UserService], + providers: [UserService, HashService], }) export class UserModule {} diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 668a7d6..2726525 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -1,4 +1,71 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; +import { RegisterUserDto } from './dto/register-user.dto'; +import { User } from './entities/user.entity'; +import { Repository } from 'typeorm'; +import { InjectRepository } from '@nestjs/typeorm'; +import { UpdateUserDto } from './dto/update-user.dto'; +import * as bcrypt from 'bcrypt'; +import { HashService } from './hash.service'; @Injectable() -export class UserService {} +export class UserService { + constructor( + @InjectRepository(User) + private readonly usersRepository: Repository, + private readonly hashService: HashService, + ) {} + + async create(createUserDto: RegisterUserDto) { + const { name, email, username, password } = createUserDto; + + const userByEmail = await this.usersRepository.findOne({ + where: { email }, + }); + if (userByEmail) { + throw new BadRequestException('Email already in use'); + } + + const userByUsername = await this.usersRepository.findOne({ + where: { username }, + }); + if (userByUsername) { + throw new BadRequestException('Username already in use'); + } + + const hashedPassword = await this.hashService.hashPassword(password); + + const user = this.usersRepository.create({ + name, + username, + email, + password: hashedPassword, + }); + + const savedUser = await this.usersRepository.save(user); + const { password: _, ...userWithoutPassword } = savedUser; + return userWithoutPassword; + } + + async getAllUsers() { + const user = await this.usersRepository.find(); + return user; + } + + async update(id: string, updateUserDto: UpdateUserDto) { + const user = await this.usersRepository.findOneBy({ id }); + if (!user) { + throw new NotFoundException(`User with id ${id} not found`); + } + + Object.assign(user, updateUserDto); + return await this.usersRepository.save(user); + } + + async remove(id: string) { + const user = await this.usersRepository.findOneBy({ id }); + if (!user) { + throw new NotFoundException(`User with id ${id} not found`); + } + await this.usersRepository.remove(user); + } +} From eb0ebc6f807ca5a41a0ca57ca0a40361a3c097af Mon Sep 17 00:00:00 2001 From: thisme8 Date: Fri, 17 Oct 2025 12:52:33 +0545 Subject: [PATCH 2/2] Resolve the PR comment in US-06 --- package.json | 2 + pnpm-lock.yaml | 106 ++++++++++++++++++++------ src/migrations/1760485409896-users.ts | 2 +- src/user/user.controller.ts | 16 ++-- 4 files changed, 92 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 9147934..024680b 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "@nestjs/mapped-types": "^2.1.0", "@nestjs/platform-express": "^11.0.1", "@nestjs/typeorm": "11.0.0", + "bcrypt": "^6.0.0", + "class-validator": "^0.14.2", "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40de5b9..2eeb589 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,22 +10,28 @@ importers: dependencies: '@nestjs/common': specifier: ^11.0.1 - version: 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': specifier: ^4.0.2 - version: 4.0.2(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 4.0.2(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': specifier: ^11.0.1 - version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/mapped-types': specifier: ^2.1.0 - version: 2.1.0(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2) + version: 2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2) '@nestjs/platform-express': specifier: ^11.0.1 - version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) '@nestjs/typeorm': specifier: 11.0.0 - version: 11.0.0(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.8)(typescript@5.9.3))) + version: 11.0.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.8)(typescript@5.9.3))) + bcrypt: + specifier: ^6.0.0 + version: 6.0.0 + class-validator: + specifier: ^0.14.2 + version: 0.14.2 pg: specifier: ^8.16.3 version: 8.16.3 @@ -56,7 +62,7 @@ importers: version: 11.0.8(chokidar@4.0.3)(typescript@5.9.3) '@nestjs/testing': specifier: ^11.0.1 - version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6) + version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6) '@types/express': specifier: ^5.0.0 version: 5.0.3 @@ -907,6 +913,9 @@ packages: '@types/supertest@6.0.3': resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + '@types/validator@13.15.3': + resolution: {integrity: sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -1281,6 +1290,10 @@ packages: resolution: {integrity: sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==} hasBin: true + bcrypt@6.0.0: + resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==} + engines: {node: '>= 18'} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -1380,6 +1393,9 @@ packages: cjs-module-lexer@2.1.0: resolution: {integrity: sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==} + class-validator@0.14.2: + resolution: {integrity: sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -2247,6 +2263,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.12.24: + resolution: {integrity: sha512-l5IlyL9AONj4voSd7q9xkuQOL4u8Ty44puTic7J88CmdXkxfGsRfoVLXHCxppwehgpb/Chdb80FFehHqjN3ItQ==} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -2413,9 +2432,17 @@ packages: node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + node-addon-api@8.5.0: + resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} + engines: {node: ^18 || ^20 || >= 21} + node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -3166,6 +3193,10 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + validator@13.15.15: + resolution: {integrity: sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==} + engines: {node: '>= 0.10'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -4003,7 +4034,7 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: file-type: 21.0.0 iterare: 1.2.1 @@ -4012,20 +4043,22 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 + optionalDependencies: + class-validator: 0.14.2 transitivePeerDependencies: - supports-color - '@nestjs/config@4.0.2(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + '@nestjs/config@4.0.2(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) dotenv: 16.4.7 dotenv-expand: 12.0.1 lodash: 4.17.21 rxjs: 7.8.2 - '@nestjs/core@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -4035,17 +4068,19 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) - '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)': + '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 + optionalDependencies: + class-validator: 0.14.2 - '@nestjs/platform-express@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)': + '@nestjs/platform-express@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.5 express: 5.1.0 multer: 2.0.2 @@ -4076,18 +4111,18 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/testing@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6)': + '@nestjs/testing@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) - '@nestjs/typeorm@11.0.0(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.8)(typescript@5.9.3)))': + '@nestjs/typeorm@11.0.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.8)(typescript@5.9.3)))': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 rxjs: 7.8.2 typeorm: 0.3.27(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.8)(typescript@5.9.3)) @@ -4271,6 +4306,8 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 + '@types/validator@13.15.3': {} + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': @@ -4668,6 +4705,11 @@ snapshots: baseline-browser-mapping@2.8.12: {} + bcrypt@6.0.0: + dependencies: + node-addon-api: 8.5.0 + node-gyp-build: 4.8.4 + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -4779,6 +4821,12 @@ snapshots: cjs-module-lexer@2.1.0: {} + class-validator@0.14.2: + dependencies: + '@types/validator': 13.15.3 + libphonenumber-js: 1.12.24 + validator: 13.15.15 + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -5838,6 +5886,8 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.12.24: {} + lines-and-columns@1.2.4: {} load-esm@1.0.2: {} @@ -5968,10 +6018,14 @@ snapshots: node-abort-controller@3.1.1: {} + node-addon-api@8.5.0: {} + node-emoji@1.11.0: dependencies: lodash: 4.17.21 + node-gyp-build@4.8.4: {} + node-int64@0.4.0: {} node-releases@2.0.23: {} @@ -6687,6 +6741,8 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + validator@13.15.15: {} + vary@1.1.2: {} walker@1.0.8: diff --git a/src/migrations/1760485409896-users.ts b/src/migrations/1760485409896-users.ts index 4e0386d..dcf285b 100644 --- a/src/migrations/1760485409896-users.ts +++ b/src/migrations/1760485409896-users.ts @@ -8,7 +8,7 @@ export class Users1760485409896 implements MigrationInterface { "name" VARCHAR(255) NOT NULL, "username" VARCHAR(255) UNIQUE NOT NULL, "email" VARCHAR(50) UNIQUE NOT NULL, - "password" VARCHAR(50) NOT NULL, + "password" VARCHAR(255) NOT NULL, "verified_at" timestamptz, "updated_at" timestamptz, "created_at" timestamptz DEFAULT now() NOT NULL diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index bcd2e36..7e7f455 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -7,26 +7,26 @@ import { UpdateUserDto } from './dto/update-user.dto'; export class UserController { constructor(private readonly usersService: UserService) {} - @Post('signup') + @Post('/') async create(@Body() createUserDto: RegisterUserDto) { const user = await this.usersService.create(createUserDto); - return { message: 'User registered successfully. Please verify your email.', user }; + return { message: 'User registered successfully. Please verify your email.', data: { user } }; } - @Get('get') + @Get('/') async getAllUsers() { - return this.usersService.getAllUsers(); + const users = await this.usersService.getAllUsers(); + return { message: 'Here are all the users.', data: { users } }; } @Patch(':id') async update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { - return this.usersService.update(id, updateUserDto); + const user = await this.usersService.update(id, updateUserDto); + return { message: 'The user has been updated successfully', data: { user } }; } @Delete(':id') async remove(@Param('id') id: string) { - return this.usersService.remove(id); + return (this.usersService.remove(id), { message: 'The user has been deleted successfully' }); } } - -