Skip to content

Commit

Permalink
update validation logic and add tests; fix miscellaneous bugs. WIP b0…
Browse files Browse the repository at this point in the history
  • Loading branch information
Ancog committed Aug 15, 2024
1 parent 088cbaf commit 534e861
Show file tree
Hide file tree
Showing 31 changed files with 554 additions and 124 deletions.
23 changes: 14 additions & 9 deletions staff/angel-patino/project/api/data/Recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ import { Schema, model, Types } from "mongoose"

const { ObjectId } = Types

const ingredientSchema = new Schema({
name: { type: String, required: true },
quantity: { type: Number, required: true },
unit: {
type: String,
required: true,
enum: ['gr', 'ml', 'l', 'tsp', 'unit']
}
})

const recipe = new Schema({
author: {
type: ObjectId,
Expand All @@ -13,12 +23,6 @@ const recipe = new Schema({
type: String,
required: true,
},

source: {
type: String,
required: true,
},

thumbnail: {
type: String,
required: true
Expand All @@ -29,10 +33,11 @@ const recipe = new Schema({
required: true
},

ingredients: [{
type: String,
ingredients: {
type: [ingredientSchema],
required: true
}],

},

description: {
type: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ export default (req, res, next) => {
.then(payload => {
const { sub: userId } = payload

const { title, source, thumbnail, cookTime, ingredients, description, rating } = req.body
const { title, thumbnail, cookTime, ingredients, description, rating } = req.body

try {
logic.createRecipe(userId, title, source, thumbnail, cookTime, ingredients, description, rating)
logic.createRecipe(userId, title, thumbnail, cookTime, ingredients, description, rating)
.then(() => res.status(201).send())
.catch(error => next(error))
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { JWT_SECRET } = process.env

export default (req, res, next) => {
try {
const toke = req.headers.authorization.slice(7)
const token = req.headers.authorization.slice(7)

jwt.verify(token, JWT_SECRET)
.then(payload => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ const { JWT_SECRET } = process.env

export default (req, res, next) => {
try {
const token = req.headers.authorization.slic(7)
const token = req.headers.authorization.slice(7)

jwt.verify(token, JWT_SECRET)
.then(payload => {
const { usb: userId } = payload
const { sub: userId } = payload

const { username } = req.body

Expand All @@ -26,7 +26,7 @@ export default (req, res, next) => {
next(error)
}
})
.catch(error => next(new CredentialsError(error.mesaage)))
.catch(error => next(new CredentialsError(error.message)))
} catch (error) {
next(error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default (req, res, next) => {
try {
const token = req.headers.authorization.slice(7)

jwt.verify(toke, JWT_SECRET)
jwt.verify(token, JWT_SECRET)
.then(payload => {
const { sub: userId } = payload

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { JWT_SECRET } = process.env

export default (req, res, next) => {
try {
const token = req.headres.authorization.slice(7)
const token = req.headers.authorization.slice(7)

jwt.verify(token, JWT_SECRET)
.then(payload => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default (req, res, next) => {
const { recipeId } = req.params

try {
logic.rateRecipe(userId, recipeId,)
logic.rateRecipe(userId, recipeId)
.then(() => res.status(204).send())
.catch(error => next(error))
} catch (error) {
Expand Down
12 changes: 6 additions & 6 deletions staff/angel-patino/project/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {

const { MONGODB_URL, PORT } = process.env

const jsonBodyParser = express.json({ strict: true, type: 'application/json' })

mongoose.connect(MONGODB_URL)
.then(() => {
const api = express()
Expand All @@ -25,23 +27,21 @@ mongoose.connect(MONGODB_URL)

api.get('/', (_, res) => res.send('Hello, RecipeBox'))

const jsonBodyParser = express.json({ strict: true, type: 'application/json' })

api.post('/users', jsonBodyParser, registerUserHandler)

api.post('/users/auth', jsonBodyParser, authenticateUserHandler)

api.get('/users/:targetUserId', getUserNameHandler)

api.patch('/profile/userId/editUsername', jsonBodyParser, editUsernameHandler)

api.get('/recipes', getAllRecipesHandler)
api.patch('/profile/:userId/editUsername', jsonBodyParser, editUsernameHandler)

api.post('/recipes', jsonBodyParser, createRecipeHandler)

api.get('/recipes', getAllRecipesHandler)

api.delete('/recipes/:recipeId', deleteRecipeHandler)

api.delete('/recipes/:recipesId/likes', toggleLikeRecipeHandler)
api.delete('/recipes/:recipeId/likes', toggleLikeRecipeHandler)

api.use(errorHandler)

Expand Down
16 changes: 10 additions & 6 deletions staff/angel-patino/project/api/logic/createRecipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ import { User, Recipe } from '../data/index.js'
import { NotFoundError, SystemError } from 'com/errors.js'
import validate from 'com/validate.js'

const createRecipe = (userId, title, source, thumbnail, cookTime, ingredients, description, rating) => {
const createRecipe = (userId, title, thumbnail, cookTime, ingredients, description, rating) => {
validate.id(userId, 'userId')
validate.text(title, 'title', 25)
validate.text(source, 'source', 25)
validate.url(thumbnail, 'image')
validate.number(cookTime, 'cookTime')
validate.arrayOfString(ingredients, 'ingredients')
validate.ingredientArray(ingredients, 'ingredients')
validate.text(description, 'description')
validate.number(rating, 'rating', { min: 1, max: 5 })
validate.rating(rating, 'rating')



Expand All @@ -23,7 +22,6 @@ const createRecipe = (userId, title, source, thumbnail, cookTime, ingredients, d
const recipe = {
author: userId,
title,
source,
thumbnail,
cookTime,
ingredients,
Expand All @@ -34,7 +32,13 @@ const createRecipe = (userId, title, source, thumbnail, cookTime, ingredients, d

return Recipe.create(recipe)
.catch((error) => { throw new SystemError(error.message) })
.then(() => { })
.then(createdRecipe => {
return User.findByIdAndUpdate(userId, {
$push: { recipeList: createdRecipe._id }
}).catch(() => {
throw new SystemError((error.message))
}).then(() => createdRecipe)
})
})

}
Expand Down
73 changes: 56 additions & 17 deletions staff/angel-patino/project/api/logic/createRecipe.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dotenv/config'
import mongoose from 'mongoose'
import mongoose, { Types } from 'mongoose'
import bcrypt from 'bcryptjs'

import { expect } from 'chai'
Expand All @@ -8,7 +8,9 @@ import { Recipe, User } from '../data/index.js'

import createRecipe from './createRecipe.js'

import { ContentError } from 'com/errors.js'
import { ContentError, NotFoundError } from 'com/errors.js'

const { ObjectId } = Types

const { MONGODB_URL_TEST } = process.env

Expand All @@ -24,41 +26,51 @@ describe('createRecipe', () => {
bcrypt.hash('123123123', 8)
.then(hash => User.create({ name: 'Super', surname: 'Chef', email: '[email protected]', username: 'Superchef', password: hash }))
.then(user =>
createRecipe(user.id, 'Hello Recipe', 'sugar', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, ['sugar', 'chocolate'], 'funcionará?', 1)
createRecipe(user.id, 'Hello Recipe', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], 'funcionará?', 1)
.then(() => Recipe.findOne())
.then(recipe => {

// Convertir cada ingrediente a un objeto simple usando map y toObject()
const ingredients = recipe.ingredients.map(ingredient => ingredient.toObject ? ingredient.toObject() : ingredient)

// Eliminar propiedades adicionales de Mongoose (_id, __v)
ingredients.forEach(ingredient => {
delete ingredient._id
delete ingredient.__v
})

expect(recipe.author.toString()).to.equal(user.id)
expect(recipe.title).to.equal('Hello Recipe')
expect(recipe.source).to.equal('sugar')
expect(recipe.thumbnail).to.equal("https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g")
expect(recipe.cookTime).to.equal(2)
expect(recipe.ingredients).to.equal(['sugar', 'chocolate'])
expect(recipe.rating).to.equal(1)
expect(ingredients).to.deep.equal([{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }])
expect(recipe.description).to.equal('funcionará?')
expect(recipe.rating).to.equal(1)


})
)
)
it('fails on non-existing user', () => {
let errorThrown

return createRecipe('Juanito', 'Hello Recipe', 'sugar', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, '100gr sugar, 50gr chocolate', 'funcionará?', 1)
return createRecipe(new ObjectId().toString(), 'Hello Recipe', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], 'funcionará?', 1)
.catch(error => errorThrown = error)
.finally(() => {
expect(errorThrown).to.be.instanceOf(NotFoundError);
expect(errorThrown.message).to.equal('user not found');
expect(errorThrown).to.be.an.instanceOf(NotFoundError)
expect(errorThrown.message).to.equal('user not found')
})
})

it('fails on invalid userId', () => {
let errorThrown

try {
createRecipe(123456, 'Hello Recipe', 'sugar, chocolate', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, '100gr sugar, 50gr chococale', 'funcionará?', 1)
createRecipe(123456, 'Hello Recipe', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], 'funcionará?', 1)
} catch (error) {
errorThrown = error
} finally {
expect(errorThrown).to.be.instanceOf(ContentError)
expect(errorThrown).to.be.an.instanceOf(ContentError)
expect(errorThrown.message).to.equal('userId is not valid')
}
})
Expand All @@ -67,11 +79,11 @@ describe('createRecipe', () => {
let errorThrown

try {
createRecipe(new ObjectId().toString(), 123456789, 'sugar, chocolate', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, '100gr sugar, 50gr chocolate', 'funcionará?', 1)
createRecipe(new ObjectId().toString(), 123456789, "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], 'funcionará?', 1)
} catch (error) {
errorThrown = error
} finally {
expect(errorThrown).to.be.instanceOf(ContentError)
expect(errorThrown).to.be.an.instanceOf(ContentError)
expect(errorThrown.message).to.equal('title is not valid')
}
})
Expand All @@ -80,11 +92,11 @@ describe('createRecipe', () => {
let errorThrown

try {
createRecipe(new ObjectId().toString(), 'Hello Recipe', 'sugar, chocolate', 123456789, 2, '100gr sugar, 50gr chocolate', 'funcionará?', 1)
createRecipe(new ObjectId().toString(), 'Hello Recipe', 123456789, 2, [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], 'funcionará?', 1)
} catch (error) {
errorThrown = error
} finally {
expect(errorThrown).to.be.instanceOf(ContentError)
expect(errorThrown).to.be.an.instanceOf(ContentError)
expect(errorThrown.message).to.equal('image is not valid')
}
})
Expand All @@ -93,15 +105,42 @@ describe('createRecipe', () => {
let errorThrown

try {
createRecipe(new ObjectId().toString(), 'Hello Recipe', 'sugar, chocolate', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, '100gr sugar, 50gr chocolate', 123456789, 1)
createRecipe(new ObjectId().toString(), 'Hello Recipe', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], 123456789, 1)
} catch (error) {
errorThrown = error
} finally {
expect(errorThrown).to.be.instanceOf(ContentError)
expect(errorThrown).to.be.an.instanceOf(ContentError)
expect(errorThrown.message).to.equal('description is not valid')
}
})

it('fails on invalid rating', () => {
let errorThrown

try {
createRecipe(new ObjectId().toString(), 'Hello Recipe', "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], 'funcionará?', 9)
} catch (error) {
errorThrown = error
} finally {
expect(errorThrown).to.be.an.instanceOf(ContentError)
expect(errorThrown.message).to.equal('rating must be a number between 1 and 5.')
}
})


it('fails on missing title', () => {
let errorThrown

try {
createRecipe(new ObjectId().toString(), '', [{ name: 'milk', quantity: 20, unit: 'ml' }, { name: 'chocolate', quantity: 1, unit: 'gr' }], "https://media.giphy.com/media/2kXOYTdyGPbIBISFn5/giphy.gif?cid=6c09b9525munegsuq607a67vn2oks57tip5c8ptumlx95ba7&ep=v1_gifs_trending&rid=giphy.gif&ct=g", 2, 'funcionará?', 1)
} catch (error) {
errorThrown = error
} finally {
expect(errorThrown).to.be.an.instanceOf(ContentError)
expect(errorThrown.message).to.equal('title is not valid')
}
})

after(() => Promise.all([Recipe.deleteMany(), User.deleteMany()]).then(() => mongoose.disconnect()))
})

16 changes: 8 additions & 8 deletions staff/angel-patino/project/api/logic/deleteRecipe.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { User, Recipe } from '../data/index.js'
import { NotFoundError, SystemError } from 'com/errors.js'
import { NotFoundError, SystemError, MatchError } from 'com/errors.js'
import validate from 'com/validate.js'
import { Types } from 'mongoose'

Expand All @@ -8,27 +8,27 @@ const { ObjectId } = Types
const deleteRecipe = (userId, recipeId) => {
validate.id(userId, 'userId')
validate.id(recipeId, 'recipeId')
//buscamos al usuario

return User.findById(userId).lean()
.catch(error => { throw new SystemError(error.message) })
.then(user => {
if (!user)
throw new NotFoundError('user not found')

return Post.findById(postId).lean()
return Recipe.findById(recipeId).lean()
.catch(error => { throw new SystemError(error.message) })
.then(recipe => {
if (!recipe) {
throw new NotFoundError('post not found')
throw new NotFoundError('recipe not found')
}
//soy yo?(username) el author del post?

if (recipe.author.toString() !== userId) {
throw new MatchError('post author does not match user')
throw new MatchError('recipe author does not match user')
}

return Recipe.deleteOne({ _id: new ObjectId(recipeId) })
return Recipe.deleteOne({ _id: recipeId })
.catch((error) => { throw new SystemError(error.message) })
.then(() => { })
.then((result) => { result })
})
})
}
Expand Down
Loading

0 comments on commit 534e861

Please sign in to comment.