diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1313588..48f6599 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,7 @@ deploy: only: - main script: - - docker-compose -p "$COMPOSE_PROJECT_NAME" up -d --build + - docker compose -p "$COMPOSE_PROJECT_NAME" up -d --build environment: name: production url: http://89.169.188.2 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 35732be..7641c10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,9 @@ "dependencies": { "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/mapped-types": "^2.1.0", "@nestjs/platform-express": "^11.0.1", + "class-validator": "^0.14.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, @@ -2368,6 +2370,26 @@ } } }, + "node_modules/@nestjs/mapped-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", + "integrity": "sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/platform-express": { "version": "11.1.9", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.9.tgz", @@ -2987,6 +3009,12 @@ "@types/superagent": "^8.1.0" } }, + "node_modules/@types/validator": { + "version": "13.15.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", @@ -4443,6 +4471,17 @@ "dev": true, "license": "MIT" }, + "node_modules/class-validator": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz", + "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==", + "license": "MIT", + "dependencies": { + "@types/validator": "^13.15.3", + "libphonenumber-js": "^1.11.1", + "validator": "^13.15.20" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -7327,6 +7366,12 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.12.30", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.30.tgz", + "integrity": "sha512-KxH7uIJFD6+cR6nhdh+wY6prFiH26A3W/W1gTMXnng2PXSwVfi5MhYkdq3Z2Y7vhBVa1/5VJgpNtI76UM2njGA==", + "license": "MIT" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -9901,6 +9946,15 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.15.23", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz", + "integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==", + "license": "MIT", + "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 b2578ff..755d5c0 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "dependencies": { "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/mapped-types": "^2.1.0", "@nestjs/platform-express": "^11.0.1", + "class-validator": "^0.14.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, diff --git a/src/app.controller.ts b/src/app.controller.ts index cce879e..f45b1f1 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,7 +1,7 @@ import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; -@Controller() +@Controller('test') export class AppController { constructor(private readonly appService: AppService) {} diff --git a/src/app.module.ts b/src/app.module.ts index 8662803..1134564 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,9 +1,10 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; +import { YachtModule } from './yacht/yacht.module'; @Module({ - imports: [], + imports: [YachtModule], controllers: [AppController], providers: [AppService], }) diff --git a/src/yacht/dto/create-yacht.dto.ts b/src/yacht/dto/create-yacht.dto.ts new file mode 100644 index 0000000..25ac48b --- /dev/null +++ b/src/yacht/dto/create-yacht.dto.ts @@ -0,0 +1,24 @@ +import { IsString, IsNumber, IsBoolean, IsUrl, Min } from 'class-validator'; + +export class CreateYachtDto { + @IsString() + name: string; + + @IsNumber() + @Min(1) + length: number; + + @IsNumber() + @Min(0) + speed: number; + + @IsNumber() + @Min(0) + minCost: number; + + @IsBoolean() + hasQuickRent: boolean; + + @IsUrl() + pictureUrl: string; +} diff --git a/src/yacht/dto/update-yacht.dto.ts b/src/yacht/dto/update-yacht.dto.ts new file mode 100644 index 0000000..702ca91 --- /dev/null +++ b/src/yacht/dto/update-yacht.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateYachtDto } from './create-yacht.dto'; + +export class UpdateYachtDto extends PartialType(CreateYachtDto) {} diff --git a/src/yacht/entities/yacht.entity.ts b/src/yacht/entities/yacht.entity.ts new file mode 100644 index 0000000..cc91567 --- /dev/null +++ b/src/yacht/entities/yacht.entity.ts @@ -0,0 +1,9 @@ +export class Yacht { + id?: number; + name: string; + length: number; + speed: number; + minCost: number; + hasQuickRent: boolean; + pictureUrl: string; +} diff --git a/src/yacht/yacht.controller.spec.ts b/src/yacht/yacht.controller.spec.ts new file mode 100644 index 0000000..e09d5e4 --- /dev/null +++ b/src/yacht/yacht.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { YachtController } from './yacht.controller'; + +describe('YachtController', () => { + let controller: YachtController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [YachtController], + }).compile(); + + controller = module.get(YachtController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/yacht/yacht.controller.ts b/src/yacht/yacht.controller.ts new file mode 100644 index 0000000..6f5ee9c --- /dev/null +++ b/src/yacht/yacht.controller.ts @@ -0,0 +1,47 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, + ParseIntPipe, +} from '@nestjs/common'; +import { YachtService } from './yacht.service'; +import { CreateYachtDto } from './dto/create-yacht.dto'; +import { UpdateYachtDto } from './dto/update-yacht.dto'; +import { Yacht } from './entities/yacht.entity'; + +@Controller('yacht') // Routes will be /yacht +export class YachtController { + constructor(private readonly yachtService: YachtService) {} + + @Post() + create(@Body() createYachtDto: CreateYachtDto): Yacht { + return this.yachtService.create(createYachtDto); + } + + @Get() + getAll(): Yacht[] { + return this.yachtService.getAll(); + } + + @Get(':id') + getById(@Param('id', ParseIntPipe) id: number): Yacht { + return this.yachtService.getById(id); + } + + @Patch(':id') + update( + @Param('id', ParseIntPipe) id: number, + @Body() updateYachtDto: UpdateYachtDto, + ): Yacht { + return this.yachtService.update(id, updateYachtDto); + } + + @Delete(':id') + remove(@Param('id', ParseIntPipe) id: number): void { + return this.yachtService.remove(id); + } +} diff --git a/src/yacht/yacht.module.ts b/src/yacht/yacht.module.ts new file mode 100644 index 0000000..f796615 --- /dev/null +++ b/src/yacht/yacht.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { YachtService } from './yacht.service'; +import { YachtController } from './yacht.controller'; + +@Module({ + controllers: [YachtController], + providers: [YachtService], +}) +export class YachtModule {} diff --git a/src/yacht/yacht.service.spec.ts b/src/yacht/yacht.service.spec.ts new file mode 100644 index 0000000..ef6a604 --- /dev/null +++ b/src/yacht/yacht.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { YachtService } from './yacht.service'; + +describe('YachtService', () => { + let service: YachtService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [YachtService], + }).compile(); + + service = module.get(YachtService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/yacht/yacht.service.ts b/src/yacht/yacht.service.ts new file mode 100644 index 0000000..164d0da --- /dev/null +++ b/src/yacht/yacht.service.ts @@ -0,0 +1,53 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { Yacht } from './entities/yacht.entity'; +import { CreateYachtDto } from './dto/create-yacht.dto'; +import { UpdateYachtDto } from './dto/update-yacht.dto'; + +@Injectable() +export class YachtService { + private yachts: Yacht[] = []; + private idCounter = 1; + + create(createYachtDto: CreateYachtDto): Yacht { + const yacht: Yacht = { + id: this.idCounter++, + ...createYachtDto, + }; + this.yachts.push(yacht); + return yacht; + } + + getAll(): Yacht[] { + return this.yachts; + } + + getById(id: number): Yacht { + const yacht = this.yachts.find((y) => y.id === id); + if (!yacht) { + throw new NotFoundException(`Yacht with ID ${id} not found`); + } + return yacht; + } + + update(id: number, updateYachtDto: UpdateYachtDto): Yacht { + const index = this.yachts.findIndex((y) => y.id === id); + if (index === -1) { + throw new NotFoundException(`Yacht with ID ${id} not found`); + } + + this.yachts[index] = { + ...this.yachts[index], + ...updateYachtDto, + }; + + return this.yachts[index]; + } + + remove(id: number): void { + const index = this.yachts.findIndex((y) => y.id === id); + if (index === -1) { + throw new NotFoundException(`Yacht with ID ${id} not found`); + } + this.yachts.splice(index, 1); + } +}