diff --git a/core/src/controllers/floors/floors.controller.ts b/core/src/controllers/floors/floors.controller.ts index 8b0e53c..f84dc32 100644 --- a/core/src/controllers/floors/floors.controller.ts +++ b/core/src/controllers/floors/floors.controller.ts @@ -9,6 +9,7 @@ import { Query, Response, Delete, + Put, } from '@nestjs/common'; import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { Mapper } from '@automapper/core'; @@ -17,7 +18,7 @@ import { ApiResponse } from '@nestjs/swagger'; import { FloorsService } from '../../entities/floors/floors.service'; import { Floor } from '../../entities/floors/models/floor.entity'; import { FloorResponseBody, FloorSearchResponseBody } from './models/floor.response.body'; -import { CreateFloorRequestBody } from './models/floor.request.body'; +import { CreateFloorRequestBody, UpdateFloorRequestBody } from './models/floor.request.body'; import { FloorsSearchRequestQuery } from './models/floor.request.query'; import { ErrorsRequestBody } from '../models/errors.response.body'; import { Response as Res } from 'express'; @@ -51,13 +52,35 @@ export class FloorsController { return this.mapper.map(floor, Floor, FloorResponseBody); } + @Put(':floorId') + @Roles(Role.ADMIN) + @ApiResponse({ status: 403, description: 'Forbidden' }) + @ApiResponse({ status: 200, type: FloorResponseBody }) + @ApiResponse({ status: 400, description: 'Bad Request', type: ErrorsRequestBody }) + async updateFloor( + @Request() req, + @Param('floorId') floorId: string, + @Body() updateFloorRequestBody: UpdateFloorRequestBody, + ) { + const floor = await this.floorsService.findOneById(floorId); + if (!floor) { + throw new NotFoundException(); + } + + floor.name = updateFloorRequestBody.name; + floor.description = updateFloorRequestBody.description; + + const newFloor = await this.floorsService.update(floor); + return this.mapper.map(newFloor, Floor, FloorResponseBody); + } + @Delete(':floorId') @Roles(Role.ADMIN) @ApiResponse({ status: 403, description: 'Forbidden', type: ErrorsRequestBody }) @ApiResponse({ status: 404, description: 'Not Found' }) @ApiResponse({ status: 200, type: FloorResponseBody }) - async deletePlant(@Response() res: Res, @Request() req, @Param('floorId') plantId: string) { - const floor = await this.floorsService.deleteFloor(plantId); + async deletePlant(@Response() res: Res, @Request() req, @Param('floorId') floorId: string) { + const floor = await this.floorsService.deleteFloor(floorId); if (!floor) { throw new NotFoundException(); } diff --git a/core/src/controllers/floors/models/floor.request.body.ts b/core/src/controllers/floors/models/floor.request.body.ts index a8e9ae4..11520e2 100644 --- a/core/src/controllers/floors/models/floor.request.body.ts +++ b/core/src/controllers/floors/models/floor.request.body.ts @@ -11,3 +11,14 @@ export class CreateFloorRequestBody { @IsString() description: string; } + +export class UpdateFloorRequestBody { + @ApiProperty({ required: true }) + @IsString() + @Matches('^[a-z0-9_-]{3,30}$') + name: string; + + @ApiProperty({ required: true }) + @IsString() + description: string; +} diff --git a/core/src/controllers/plants/models/plant.request.body.ts b/core/src/controllers/plants/models/plant.request.body.ts index 3c13046..c9b05c7 100644 --- a/core/src/controllers/plants/models/plant.request.body.ts +++ b/core/src/controllers/plants/models/plant.request.body.ts @@ -66,3 +66,22 @@ export class CreatePlantRequestBody { @Type(() => CreatePlantClassificationRequestBody) classification: CreatePlantClassificationRequestBody; } + +export class UpdatePlantRequestBody { + @ApiProperty({ required: true }) + @IsString() + @Matches(/^[^\s][a-z0-9_ -]{1,30}[^\s]$/) + name: string; + + @ApiProperty({ required: true }) + @IsString() + description: string; + + @ApiProperty({ required: true, type: CreatePlantClassificationRequestBody }) + @IsDefined() + @IsNotEmptyObject() + @IsObject() + @ValidateNested() + @Type(() => CreatePlantClassificationRequestBody) + classification: CreatePlantClassificationRequestBody; +} diff --git a/core/src/controllers/plants/plants.controller.ts b/core/src/controllers/plants/plants.controller.ts index a25ce99..f8a3604 100644 --- a/core/src/controllers/plants/plants.controller.ts +++ b/core/src/controllers/plants/plants.controller.ts @@ -9,6 +9,7 @@ import { Post, Query, Delete, + Put, } from '@nestjs/common'; import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { Mapper } from '@automapper/core'; @@ -17,7 +18,7 @@ import { ApiResponse } from '@nestjs/swagger'; import { PlantsService } from '../../entities/plants/plants.service'; import { Plant } from '../../entities/plants/models/plant.entity'; import { PlantResponseBody, PlantSearchResponseBody } from './models/plant.response.body'; -import { CreatePlantRequestBody } from './models/plant.request.body'; +import { CreatePlantRequestBody, UpdatePlantRequestBody } from './models/plant.request.body'; import { PlantsSearchRequestQuery } from './models/plant.request.query'; import { ErrorsRequestBody } from '../models/errors.response.body'; import { Response as Res } from 'express'; @@ -51,6 +52,29 @@ export class PlantsController { return this.mapper.map(plant, Plant, PlantResponseBody); } + @Put(':plantId') + @Roles(Role.ADMIN) + @ApiResponse({ status: 403, description: 'Forbidden' }) + @ApiResponse({ status: 201, type: PlantResponseBody }) + @ApiResponse({ status: 400, description: 'Bad Request', type: ErrorsRequestBody }) + async updatePlant( + @Request() req, + @Param('plantId') plantId: string, + @Body() updatePlantRequestBody: UpdatePlantRequestBody, + ) { + const plant = await this.plantsService.findOneById(plantId); + if (!plant) { + throw new NotFoundException(); + } + + plant.name = updatePlantRequestBody.name; + plant.description = updatePlantRequestBody.description; + plant.classification = updatePlantRequestBody.classification; + + const newPlant = await this.plantsService.update(plant); + return this.mapper.map(newPlant, Plant, PlantResponseBody); + } + @Delete(':plantId') @Roles(Role.ADMIN) @ApiResponse({ status: 403, description: 'Forbidden' }) diff --git a/core/src/controllers/varieties/models/variety.request.body.ts b/core/src/controllers/varieties/models/variety.request.body.ts index c535cd9..1cc5923 100644 --- a/core/src/controllers/varieties/models/variety.request.body.ts +++ b/core/src/controllers/varieties/models/variety.request.body.ts @@ -146,3 +146,42 @@ export class CreateVarietyRequestBody { @Type(() => CreateVarietyCultureRequestBody) culture: CreateVarietyCultureRequestBody; } + +export class UpdateVarietyRequestBody { + @ApiProperty({ required: true }) + @IsString() + @Matches(new RegExp('^[0-9a-fA-F]{24}$')) + @Validate(PlantExistsRule) + plant: string; + + @ApiProperty({ required: true }) + @IsString() + @Matches('^[a-z0-9_-]{3,30}$') + name: string; + + @ApiProperty({ required: true, enum: Country }) + origin: Country; + + @ApiProperty({ required: true }) + @IsString() + description: string; + + @ApiProperty({ required: true, enum: VarietyPrecocity }) + precocity: VarietyPrecocity; + + @ApiProperty({ required: true, type: CreateVarietyRequirementRequestBody }) + @IsDefined() + @IsNotEmptyObject() + @IsObject() + @ValidateNested() + @Type(() => CreateVarietyRequirementRequestBody) + requirement: CreateVarietyRequirementRequestBody; + + @ApiProperty({ required: true, type: CreateVarietyCultureRequestBody }) + @IsDefined() + @IsNotEmptyObject() + @IsObject() + @ValidateNested() + @Type(() => CreateVarietyCultureRequestBody) + culture: CreateVarietyCultureRequestBody; +} diff --git a/core/src/controllers/varieties/varieties.controller.ts b/core/src/controllers/varieties/varieties.controller.ts index 03b0b96..dd23986 100644 --- a/core/src/controllers/varieties/varieties.controller.ts +++ b/core/src/controllers/varieties/varieties.controller.ts @@ -9,6 +9,7 @@ import { Query, Response, Delete, + Put, } from '@nestjs/common'; import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { Mapper } from '@automapper/core'; @@ -17,9 +18,9 @@ import { ApiResponse } from '@nestjs/swagger'; import { VarietiesService } from '../../entities/varieties/varieties.service'; import { Variety } from '../../entities/varieties/models/variety.entity'; import { VarietyResponseBody, VarietySearchResponseBody } from './models/variety.response.body'; -import { CreateVarietyRequestBody } from './models/variety.request.body'; +import { CreateVarietyRequestBody, UpdateVarietyRequestBody } from './models/variety.request.body'; import { VarietiesSearchRequestQuery } from './models/variety.request.query'; -import mongoose from 'mongoose'; +import mongoose, { Types } from 'mongoose'; import { ErrorsRequestBody } from '../models/errors.response.body'; import { Roles } from '../../auth/roles/roles.decorator'; import { Role } from '../../auth/roles/role.enum'; @@ -59,12 +60,42 @@ export class VarietiesController { return this.mapper.map(plant, Variety, VarietyResponseBody); } + @Put(':varietyId') + @Roles(Role.ADMIN) + @ApiResponse({ status: 403, description: 'Forbidden' }) + @ApiResponse({ status: 404, description: 'Not Found' }) + @ApiResponse({ status: 200, type: VarietyResponseBody }) + async updateVariety( + @Request() req, + @Param('varietyId') varietyId: string, + @Body() updateVarietyRequestBody: UpdateVarietyRequestBody, + ) { + const variety = await this.varietiesService.findOneById(varietyId); + if (!variety) { + throw new NotFoundException(); + } + + variety.plant = new Types.ObjectId(updateVarietyRequestBody.plant); + variety.name = updateVarietyRequestBody.name; + variety.description = updateVarietyRequestBody.description; + variety.origin = updateVarietyRequestBody.origin; + variety.culture = updateVarietyRequestBody.culture; + variety.requirement = { + ...updateVarietyRequestBody.requirement, + floors: updateVarietyRequestBody.requirement.floors.map((floor) => new mongoose.Types.ObjectId(floor)), + }; + variety.precocity = updateVarietyRequestBody.precocity; + + const newPlant = await this.varietiesService.update(variety); + return this.mapper.map(newPlant, Variety, VarietyResponseBody); + } + @Delete(':varietyId') @Roles(Role.ADMIN) @ApiResponse({ status: 403, description: 'Forbidden' }) @ApiResponse({ status: 404, description: 'Not Found' }) @ApiResponse({ status: 200, type: VarietyResponseBody }) - async deletePlant(@Request() req, @Param('varietyId') varietyId: string) { + async deleteVariety(@Request() req, @Param('varietyId') varietyId: string) { const variety = await this.varietiesService.delete(varietyId); if (!variety) { throw new NotFoundException(); diff --git a/core/src/entities/floors/floors.service.ts b/core/src/entities/floors/floors.service.ts index 8c11465..17eddd5 100644 --- a/core/src/entities/floors/floors.service.ts +++ b/core/src/entities/floors/floors.service.ts @@ -16,10 +16,23 @@ export class FloorsService extends BaseEntityService { super(); } - async create(Floor: Floor): Promise { + async create(floor: Floor): Promise { try { - Floor._id = new mongoose.Types.ObjectId(); - return await this.floorModel.create(Floor); + floor._id = new mongoose.Types.ObjectId(); + return await this.floorModel.create(floor); + } catch (exception) { + if (exception.code === 11000) { + throw new ConflictException(); + } + throw exception; + } + } + + async update(floor: Floor): Promise { + try { + floor.updatedAt = new Date(); + await this.floorModel.updateOne(floor); + return await this.findOneById(floor._id.toString()); } catch (exception) { if (exception.code === 11000) { throw new ConflictException(); diff --git a/core/src/entities/plants/plants.service.ts b/core/src/entities/plants/plants.service.ts index 074432c..9473816 100644 --- a/core/src/entities/plants/plants.service.ts +++ b/core/src/entities/plants/plants.service.ts @@ -22,10 +22,23 @@ export class PlantsService extends BaseEntityService { super(); } - async create(Plant: Plant): Promise { + async create(plant: Plant): Promise { try { - Plant._id = new mongoose.Types.ObjectId(); - return await this.plantModel.create(Plant); + plant._id = new mongoose.Types.ObjectId(); + return await this.plantModel.create(plant); + } catch (exception) { + if (exception.code === 11000) { + throw new ConflictException(); + } + throw exception; + } + } + + async update(plant: Plant): Promise { + try { + plant.updatedAt = new Date(); + await this.plantModel.updateOne(plant); + return await this.findOneById(plant._id.toString()); } catch (exception) { if (exception.code === 11000) { throw new ConflictException(); diff --git a/core/src/entities/varieties/varieties.service.ts b/core/src/entities/varieties/varieties.service.ts index 2a76851..f2d4064 100644 --- a/core/src/entities/varieties/varieties.service.ts +++ b/core/src/entities/varieties/varieties.service.ts @@ -29,10 +29,23 @@ export class VarietiesService extends BaseEntityService { super(); } - async create(plant: Variety): Promise { + async create(variety: Variety): Promise { try { - plant._id = new mongoose.Types.ObjectId(); - return await this.varietyModel.create(plant); + variety._id = new mongoose.Types.ObjectId(); + return await this.varietyModel.create(variety); + } catch (exception) { + if (exception.code === 11000) { + throw new ConflictException(); + } + throw exception; + } + } + + async update(variety: Variety): Promise { + try { + variety.updatedAt = new Date(); + await this.varietyModel.updateOne(variety); + return await this.findOneById(variety._id.toString()); } catch (exception) { if (exception.code === 11000) { throw new ConflictException();