diff --git a/.prettierrc b/.prettierrc index dcb7279..3ddabd6 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,5 @@ { "singleQuote": true, - "trailingComma": "all" + "trailingComma": "all", + "endOfLine": "lf" } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4789053..2541629 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ "@nestjs/platform-express": "^11.0.1", "@nestjs/swagger": "^11.2.0", "@prisma/client": "^6.11.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.2", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, @@ -3380,6 +3382,11 @@ "@types/superagent": "^8.1.0" } }, + "node_modules/@types/validator": { + "version": "13.15.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.2.tgz", + "integrity": "sha512-y7pa/oEJJ4iGYBxOpfAKn5b9+xuihvzDVnC/OSvlVnGxVg0pOqmjiMafiJ1KVNQEaPZf9HsEp5icEwGg8uIe5Q==" + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", @@ -5112,6 +5119,21 @@ "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", "dev": true }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "node_modules/class-validator": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz", + "integrity": "sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==", + "dependencies": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.11.1", + "validator": "^13.9.0" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -8041,6 +8063,11 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.12.10", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.10.tgz", + "integrity": "sha512-E91vHJD61jekHHR/RF/E83T/CMoaLXT7cwYA75T4gim4FZjnM6hbJjVIGg7chqlSqRsSvQ3izGmOjHy1SQzcGQ==" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -10711,6 +10738,14 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.15.15", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", + "integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 364683e..f4e95eb 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "@nestjs/platform-express": "^11.0.1", "@nestjs/swagger": "^11.2.0", "@prisma/client": "^6.11.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.2", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, diff --git a/src/app.module.ts b/src/app.module.ts index ead0157..6613bd8 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -4,9 +4,10 @@ import { AppService } from './app.service'; import { PrismaModule } from './prisma/prisma.module'; import { HealthModule } from './health/health.module'; import { HealthController } from './health/health.controller'; +import { UsersModule } from './modules/users/users.module'; @Module({ - imports: [PrismaModule, HealthModule], + imports: [PrismaModule, HealthModule, UsersModule], controllers: [AppController, HealthController], providers: [AppService], }) diff --git a/src/main.ts b/src/main.ts index f76bc8d..e540551 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,4 @@ +import 'reflect-metadata'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; diff --git a/src/modules/users-management/index.ts b/src/modules/users-management/index.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/modules/users/controllers/users.controller.spec.ts b/src/modules/users/controllers/users.controller.spec.ts new file mode 100644 index 0000000..3e27c39 --- /dev/null +++ b/src/modules/users/controllers/users.controller.spec.ts @@ -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); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/modules/users/controllers/users.controller.ts b/src/modules/users/controllers/users.controller.ts new file mode 100644 index 0000000..1a26add --- /dev/null +++ b/src/modules/users/controllers/users.controller.ts @@ -0,0 +1,47 @@ +import { + Controller, + Get, + Post, + Body, + Param, + Patch, + Delete, + ParseIntPipe, +} from '@nestjs/common'; +import { UsersService } from '../services/users.service'; +import { CreateUserDto } from '../dtos/create-user.dto'; +import { UpdateUserDto } from '../dtos/update-user.dto'; +import { Users } from '@prisma/client'; + +@Controller('users') +export class UsersController { + constructor(private readonly usersService: UsersService) {} + + @Post() + create(@Body() dto: CreateUserDto): Promise { + return this.usersService.create(dto); + } + + @Get() + findAll(): Promise { + return this.usersService.findAll(); + } + + @Get() + findOne(@Param('id', ParseIntPipe) user_id: number): Promise { + return this.usersService.findOne(user_id); + } + + @Patch(':user_id') + update( + @Param('user_id', ParseIntPipe) user_id: number, + @Body() dto: UpdateUserDto, + ): Promise { + return this.usersService.update(user_id, dto); + } + + @Delete(':user_id') + remove(@Param('user_id', ParseIntPipe) user_id: number): Promise { + return this.usersService.remove(user_id); + } +} diff --git a/src/modules/users/dtos/create-user.dto.ts b/src/modules/users/dtos/create-user.dto.ts new file mode 100644 index 0000000..e373b08 --- /dev/null +++ b/src/modules/users/dtos/create-user.dto.ts @@ -0,0 +1,21 @@ +import { IsString, IsNotEmpty, IsEmail, IsPhoneNumber } from 'class-validator'; + +export class CreateUserDto { + @IsString() + @IsNotEmpty() + first_name: string; + + @IsString() + @IsNotEmpty() + last_name: string; + + @IsEmail() + email: string; + + @IsPhoneNumber() + @IsNotEmpty() + phone_number: number; + + @IsString() + residence: string; +} diff --git a/src/modules/users/dtos/update-user.dto.ts b/src/modules/users/dtos/update-user.dto.ts new file mode 100644 index 0000000..78ab602 --- /dev/null +++ b/src/modules/users/dtos/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/src/modules/users/services/users.service.spec.ts b/src/modules/users/services/users.service.spec.ts new file mode 100644 index 0000000..62815ba --- /dev/null +++ b/src/modules/users/services/users.service.spec.ts @@ -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); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/modules/users/services/users.service.ts b/src/modules/users/services/users.service.ts new file mode 100644 index 0000000..02f905d --- /dev/null +++ b/src/modules/users/services/users.service.ts @@ -0,0 +1,39 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { CreateUserDto } from '../dtos/create-user.dto'; +import { UpdateUserDto } from '../dtos/update-user.dto'; +import { PrismaService } from 'src/prisma/prisma.service'; +import { Users } from '@prisma/client'; + +@Injectable() +export class UsersService { + constructor(private readonly prisma: PrismaService) {} + + create(dto: CreateUserDto): Promise { + return this.prisma.users.create({ data: dto }); + } + + findAll(): Promise { + return this.prisma.users.findMany(); + } + + async findOne(user_id: number): Promise { + const user = await this.prisma.users.findUnique({ where: { user_id } }); + if (!user) { + throw new NotFoundException(`User #${user_id} not found`); + } + return user; + } + + async update(user_id: number, dto: UpdateUserDto): Promise { + await this.findOne(user_id); + return this.prisma.users.update({ + where: { user_id }, + data: dto, + }); + } + + async remove(user_id: number): Promise { + await this.findOne(user_id); + return this.prisma.users.delete({ where: { user_id } }); + } +} diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts new file mode 100644 index 0000000..7a5751a --- /dev/null +++ b/src/modules/users/users.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { UsersService } from './services/users.service'; +import { UsersController } from './controllers/users.controller'; +import { PrismaModule } from 'src/prisma/prisma.module'; + +@Module({ + imports: [PrismaModule], + providers: [UsersService], + controllers: [UsersController], +}) +export class UsersModule {} diff --git a/tsconfig.json b/tsconfig.json index e4dbf2e..e387bd3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "module": "commonjs", + "moduleResolution": "node", "declaration": true, "removeComments": true, "emitDecoratorMetadata": true,