diff --git a/src/controllers/RecipeController.ts b/src/controllers/RecipeController.ts new file mode 100644 index 0000000..03a88d1 --- /dev/null +++ b/src/controllers/RecipeController.ts @@ -0,0 +1,76 @@ +import { Entity } from "typeorm"; +import { RecipeDto } from "../dtos/RecipeDto.js"; +import { RecipeDtoEntityMapper } from "../mappers/RecipeDtoEntityMapper.js"; +import { RecipeRepository } from "../repositories/RecipeRepository.js"; +import { RecipeEntity } from "../entities/RecipeEntity.js"; +import { ValidationError } from "../errors/httpErrors.js"; +import { RecipeInstructionStepDto } from "../dtos/RecipeInstructionStepDto.js"; + +/** + * Controls all user specific actions + */ +export class RecipeController { + constructor( + private repository: RecipeRepository, + private mapper: RecipeDtoEntityMapper + ) {} + + /** + * Load list of all recipes + * @returns List of all recipes + */ + async getAllRecipes(){ + const recipeEntities = await this.repository.findAll(); + let recipeDtos : RecipeDto[] = []; + recipeEntities.forEach(recipeEntity => { + recipeDtos.push(this.mapper.toDto(recipeEntity)); + }); + return recipeDtos; + } + + /** + * Create a new recipe + * @param dto RecipeDto containing the new recipe + */ + async createRecipe(dto : RecipeDto){ + if(!this.isRecipeDtoValid(dto)){ + throw new ValidationError("recipe data is not valid!") + } + const recipeEntity = this.mapper.toEntity(dto) + const entity = await this.repository.create(recipeEntity); + return this.mapper.toDto(entity); + } + + protected isRecipeDtoValid(dto :RecipeDto) : boolean { + let isValid = true; + if(dto.title == undefined + || dto.title.length == 0 + || dto.amount == undefined + || dto.amountDescription == undefined + || dto.amountDescription.length == 0 + || !this.isInstructionsValid(dto.instructions) + ){ + isValid = false; + } + + // @todo ingredient groups + + return isValid; + } + protected isInstructionsValid(instructions: RecipeInstructionStepDto[]|undefined) : boolean { + if(instructions == undefined || instructions.length == 0){ + return false; + } + let isValid = true; + instructions.forEach(step =>{ + if(step.text == undefined + || step.text.length == 0 + || step.sortOrder == undefined + ){ + isValid = false; + } + }); + + return isValid; + } +} \ No newline at end of file diff --git a/src/dtos/RecipeDto.ts b/src/dtos/RecipeDto.ts index 8cd632f..beb3be6 100644 --- a/src/dtos/RecipeDto.ts +++ b/src/dtos/RecipeDto.ts @@ -7,7 +7,7 @@ import { RecipeInstructionStepDto } from "./RecipeInstructionStepDto.js"; */ export class RecipeDto extends AbstractDto { - title?: string; + title!: string; amount?: number amountDescription?: string; instructions?: RecipeInstructionStepDto[]; diff --git a/src/endpoints/RecipePoint.ts b/src/endpoints/RecipePoint.ts index e69de29..8dc088a 100644 --- a/src/endpoints/RecipePoint.ts +++ b/src/endpoints/RecipePoint.ts @@ -0,0 +1,26 @@ +import { Router } from "express"; +import { RecipeRepository } from "../repositories/RecipeRepository.js"; +import { RecipeDtoEntityMapper } from "../mappers/RecipeDtoEntityMapper.js"; +import { RecipeController } from "../controllers/RecipeController.js"; +import { asyncHandler } from "../utils/asyncHandler.js"; + +/** + * Handles all user related routes + */ +const router = Router(); + +// Inject repo + mapper here +const recipeRepository = new RecipeRepository(); +const recipeDtoEntityMapper = new RecipeDtoEntityMapper(); +const recipeController = new RecipeController(recipeRepository, recipeDtoEntityMapper); + +/** + * Create a new user + */ +router.get( + "/", + asyncHandler(async (req, res) => { + const response = await recipeController.getAllRecipes(); + res.status(201).json(response); + }) +); \ No newline at end of file diff --git a/src/mappers/RecipeDtoEntityMapper.ts b/src/mappers/RecipeDtoEntityMapper.ts new file mode 100644 index 0000000..f98cfdb --- /dev/null +++ b/src/mappers/RecipeDtoEntityMapper.ts @@ -0,0 +1,31 @@ +import { RecipeDto } from "../dtos/RecipeDto.js"; +import { RecipeEntity } from "../entities/RecipeEntity.js"; +import { ValidationError } from "../errors/httpErrors.js"; +import { AbstractDtoEntityMapper } from "./AbstractDtoEntityMapper.js"; + +export class RecipeDtoEntityMapper extends AbstractDtoEntityMapper{ + toDto(entity: RecipeEntity): RecipeDto { + const dto = new RecipeDto(); + this.mapBaseEntityToDto(entity, dto); + + dto.title = entity.title; + dto.amount = entity.amount + dto.amountDescription = dto.amountDescription; + + + return dto; + } + + toEntity(dto: RecipeDto): RecipeEntity { + const entity = new RecipeEntity(); + this.mapBaseDtoToEntity(dto, entity); + + + entity.title = dto.title; + entity.amount = dto.amount + entity.amountDescription = dto.amountDescription; + + return entity; + } + +} \ No newline at end of file diff --git a/src/mappers/UserDtoEntityMapper.ts b/src/mappers/UserDtoEntityMapper.ts index e6791e8..927e4f6 100644 --- a/src/mappers/UserDtoEntityMapper.ts +++ b/src/mappers/UserDtoEntityMapper.ts @@ -1,7 +1,6 @@ import { AbstractDtoEntityMapper } from "./AbstractDtoEntityMapper.js"; import { UserEntity } from "../entities/UserEntity.js"; import { UserDto } from "../dtos/UserDto.js"; -import { ValidationError } from "../errors/httpErrors.js"; export class UserDtoEntityMapper extends AbstractDtoEntityMapper { toDto(entity: UserEntity): UserDto {