From edabdbd4f8b6eddc0d866ecaefc270835a591c21 Mon Sep 17 00:00:00 2001 From: Berlem Date: Mon, 25 Mar 2024 18:31:24 +0100 Subject: [PATCH] logic create recipe front and back #407 --- .../api/handlers/createRecipeHandler.js | 21 +++++++ .../project/api/logic/createRecipe.js | 26 ++++++++ .../project/api/logic/createRecipe.spec.js | 61 +++++++++++++++++++ .../project/api/logic/createRecipe.test.js | 16 +++++ .../project/api/test/create-recipe.test.sh | 52 ++++++++++++++++ .../project/app/src/logic/createRecipe.js | 42 +++++++++++++ 6 files changed, 218 insertions(+) create mode 100644 staff/belen-ivars/project/api/handlers/createRecipeHandler.js create mode 100644 staff/belen-ivars/project/api/logic/createRecipe.js create mode 100644 staff/belen-ivars/project/api/logic/createRecipe.spec.js create mode 100644 staff/belen-ivars/project/api/logic/createRecipe.test.js create mode 100755 staff/belen-ivars/project/api/test/create-recipe.test.sh create mode 100644 staff/belen-ivars/project/app/src/logic/createRecipe.js diff --git a/staff/belen-ivars/project/api/handlers/createRecipeHandler.js b/staff/belen-ivars/project/api/handlers/createRecipeHandler.js new file mode 100644 index 000000000..3ac0add9c --- /dev/null +++ b/staff/belen-ivars/project/api/handlers/createRecipeHandler.js @@ -0,0 +1,21 @@ +import { ContentError, NotFoundError } from "com/errors.js"; +import logic from "../logic/index.js"; +import { errors } from 'com' + +export default async (req, res) => { + const { author, title, description, image } = req.body + + try { + await logic.createRecipe(author, title, description, image) + + res.status(201).send() + } catch (error) { + let status = 500 + if (error instanceof NotFoundError) + status = 404 + if (error instanceof ContentError || error instanceof TypeError) + status = 500 + + res.status(status).json({ error: error.constructor.name, message: error.message }) + } +} \ No newline at end of file diff --git a/staff/belen-ivars/project/api/logic/createRecipe.js b/staff/belen-ivars/project/api/logic/createRecipe.js new file mode 100644 index 000000000..b496f024b --- /dev/null +++ b/staff/belen-ivars/project/api/logic/createRecipe.js @@ -0,0 +1,26 @@ +import { validate, errors } from 'com' +import { Recipe, User } from '../data/models.js' +const { ContentError, NotFoundError } = errors + +async function createRecipe(userId, title, description, image) { + validate.text(title, 'title') + validate.text(description, 'description') + validate.text(image, 'image') + validate.id(userId, 'id') + + const user = await User.findById(userId) + + if (!user) + throw new NotFoundError('user not found') + console.log('user founded') + + let recipe + + try { + recipe = await Recipe.create({ author: userId, title, description, image }) + } catch (error) { + throw new ContentError('recipe cannot be published') + } +} + +export default createRecipe \ No newline at end of file diff --git a/staff/belen-ivars/project/api/logic/createRecipe.spec.js b/staff/belen-ivars/project/api/logic/createRecipe.spec.js new file mode 100644 index 000000000..0bd4a64c1 --- /dev/null +++ b/staff/belen-ivars/project/api/logic/createRecipe.spec.js @@ -0,0 +1,61 @@ +import dotenv from 'dotenv' +dotenv.config() + +import mongoose, { mongo } from 'mongoose' + +import { expect } from 'chai' +import bcrypt from 'bcryptjs' +import random from './helpers/random.js' +import createRecipe from './createRecipe.js' +import { errors } from 'com' +import { User, Recipe } from '../data/models.js' +import { NotFoundError } from 'com/errors.js' +const { ObjectId } = mongoose.Types +const { DuplicityError } = errors + +describe('createRecipe', () => { + before(async () => await mongoose.connect(process.env.TEST_MONGODB_URL)) + beforeEach(async () => await User.deleteMany()) + + it('on success', async () => { + const name = random.name() + const email = random.email() + const password = random.password() + const user = await User.create({ name, email, password }) + + const title = random.name() + const description = random.text() + const image = random.image() + const author = user.id + + let recipe + try { + recipe = await createRecipe(author, title, description, image) + } catch (error) { + expect(recipe).to.exist + expect(recipe.title).to.equal(title) + expect(recipe.image).to.equal(image) + expect(recipe.description).to.equal(description) + expect(author).to.equal(user.id) + } + + }) + + it('fails on non existing user', async () => { + + const title = random.name() + const description = random.text() + const image = random.image() + const author = new ObjectId().toString() + + try { + await createRecipe(author, title, description, image) + throw new Error('should not reach this point') + } catch (error) { + expect(error).to.be.instanceOf(NotFoundError) + expect(error.message).to.equal('user not found') + } + }) + + after(async () => await mongoose.disconnect()) +}) \ No newline at end of file diff --git a/staff/belen-ivars/project/api/logic/createRecipe.test.js b/staff/belen-ivars/project/api/logic/createRecipe.test.js new file mode 100644 index 000000000..389c0ec39 --- /dev/null +++ b/staff/belen-ivars/project/api/logic/createRecipe.test.js @@ -0,0 +1,16 @@ +import dotenv from 'dotenv' +dotenv.config() +import mongoose from 'mongoose' + +import createRecipe from './createRecipe.js' + +(async () => { + await mongoose.connect(process.env.MONGODB_URL) + try { + await createRecipe('65d655fac1dd88f9aee917d6', 'Colors', 'Persona con pintura corporal', 'https://www.pexels.com/es-es/foto/persona-con-pintura-corporal-1209843/') + + console.log('recipe has been published') + } catch (error) { + console.log(error) + } +})() \ No newline at end of file diff --git a/staff/belen-ivars/project/api/test/create-recipe.test.sh b/staff/belen-ivars/project/api/test/create-recipe.test.sh new file mode 100755 index 000000000..a808e9db3 --- /dev/null +++ b/staff/belen-ivars/project/api/test/create-recipe.test.sh @@ -0,0 +1,52 @@ +source pepetest.sh + +TEST 'create-recipe' + +CASE 'success on current user' + +curl 'http://localhost:9000/recipes' \ +-H 'Content-Type: application/json' \ +-d '{"author": "65d655fac1dd88f9aee917d6", "title": "Colors", "description": "Persona con pintura corporal", "image":"https://www.pexels.com/es-es/foto/persona-con-pintura-corporal-1209843/"}' \ +-v + +# > POST /recipes HTTP/1.1 +# > Host: localhost:9000 +# > User-Agent: curl/8.4.0 +# > Accept: */* +# > Content-Type: application/json +# > Content-Length: 187 +# > +# < HTTP/1.1 201 Created +# < X-Powered-By: Express +# < Access-Control-Allow-Origin: * +# < Date: Thu, 21 Mar 2024 17:45:59 GMT +# < Connection: keep-alive +# < Keep-Alive: timeout=5 +# < Content-Length: 0 + +CASE "fail on non existing user" + +curl 'http://localhost:9000/recipes' \ +-H 'Content-Type: application/json' \ +-d '{"author": "65d655fac1dd88f9aee917d7", "title": "Colors", "description": "Persona con pintura corporal", "image":"https://www.pexels.com/es-es/foto/persona-con-pintura-corporal-1209843/"}' \ +-v + +# > POST /recipes HTTP/1.1 +# > Host: localhost:9000 +# > User-Agent: curl/8.4.0 +# > Accept: */* +# > Content-Type: application/json +# > Content-Length: 187 +# > +# < HTTP/1.1 404 Not Found +# < X-Powered-By: Express +# < Access-Control-Allow-Origin: * +# < Content-Type: application/json; charset=utf-8 +# < Content-Length: 52 +# < ETag: W/"34-Cs2INrsYwSHLSHCKVUFPEWh9NjI" +# < Date: Thu, 21 Mar 2024 17:45:59 GMT +# < Connection: keep-alive +# < Keep-Alive: timeout=5 +# < +# * Connection #0 to host localhost left intact +# {"error":"NotFoundError","message":"user not found"}% \ No newline at end of file diff --git a/staff/belen-ivars/project/app/src/logic/createRecipe.js b/staff/belen-ivars/project/app/src/logic/createRecipe.js new file mode 100644 index 000000000..5606684ef --- /dev/null +++ b/staff/belen-ivars/project/app/src/logic/createRecipe.js @@ -0,0 +1,42 @@ +import { API_URL } from "../utils/constants" +import { errors } from 'com' +import session from "./session" + +const { SystemError } = errors + + +export default async function createRecipe(author, title, description, image) { + return (async () => { + const req = { + method: 'POST', + headers: { + Authorization: `Bearer ${session.token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ author, title, description, image }) + } + + let res + + try { + res = await fetch(`${API_URL}/recipes`, req) + } catch (error) { + throw new SystemError(error.message) + } + + if (!res.ok) { + let body + + try { + body = await res.json() + } catch (error) { + throw new SystemError(errors.message) + } + + throw new errors[body.error](body.message) + } + + })() + + +} \ No newline at end of file