Refactor validators

main
Ashelyn Dawn 4 years ago
parent 9ce70cefe2
commit b59134dc5e

@ -2,16 +2,15 @@ const router = require('express-promise-router')()
const parseJSON = require('body-parser').json()
const db = require('../db')
const {validationResult} = require('express-validator')
const validate = require('./middleware/validators')
const loginValidation = [validate.emailRestrictions, validate.passwordRestrictions]
router.post('/', parseJSON, loginValidation, async (req, res) => {
const errors = validationResult(req)
if(!errors.isEmpty())
return res.status(422).json({errors: errors.array()})
const loginValidation = [
validate.validEmail('email'),
validate.validPassword('password'),
validate.handleApiError
]
router.post('/', parseJSON, loginValidation, async (req, res) => {
const user = await db.user.login(
req.body.email,
req.body.password

@ -2,20 +2,17 @@ const router = module.exports = require('express-promise-router')()
const parseJSON = require('body-parser').json()
const db = require('../db')
const {validationResult} = require('express-validator')
const validate = require('./middleware/validators')
router.get('/', async (req, res)=>{
res.json(req.cart);
})
const cartAddValidators = [validate.countInt]
const cartAddValidators = [
validate.positiveInteger('count'),
validate.handleApiError
]
router.post('/add/:item_uuid', parseJSON, cartAddValidators, async (req, res) => {
// Check form input
const errors = validationResult(req)
if(!errors.isEmpty())
return res.status(422).json({errors: errors.array()})
// Ensure session
if(!req.session.uuid)
await db.session.create(req)
@ -36,4 +33,4 @@ router.post('/remove/:item_uuid', async (req, res) => {
const cart = await db.cart.removeItemFromCart(req.cart.uuid, req.params.item_uuid);
res.json(cart)
})
})

@ -2,7 +2,6 @@ const router = module.exports = require('express-promise-router')()
const parseJSON = require('body-parser').json()
const db = require('../db')
const {validationResult} = require('express-validator')
const validate = require('./middleware/validators')
router.get('/', async (req, res) => {
@ -12,16 +11,12 @@ router.get('/', async (req, res) => {
})
const newCategoryValidators = [
validate.urlSlugRestrictions,
validate.nameRestrictions,
validate.descriptionRestrictions
validate.validUrlSlug('urlslug'),
validate.requiredString('name'),
validate.requiredString('description'),
validate.handleApiError
]
router.post('/', parseJSON, newCategoryValidators, async (req, res) => {
const errors = validationResult(req)
if(!errors.isEmpty())
return res.status(422).json({errors: errors.array()})
const category = await db.category.create(
req.body.name,
req.body.urlslug,
@ -39,4 +34,4 @@ router.put('/:category_uuid/items/:item_uuid', async (req, res) => {
router.delete('/:category_uuid/items/:item_uuid', async (req, res) => {
const category = await db.category.removeItem(req.params.category_uuid, req.params.item_uuid);
res.json(category)
})
})

@ -2,7 +2,6 @@ const router = module.exports = require('express-promise-router')()
const parseJSON = require('body-parser').json()
const db = require('../db')
const {validationResult} = require('express-validator')
const validate = require('./middleware/validators')
const upload = require('multer')({
@ -20,19 +19,15 @@ router.get('/', async (req, res) => {
})
const newItemValidators = [
validate.urlSlugRestrictions,
validate.validUrlSlug('urlslug'),
validate.publishedBool,
validate.priceCentsInt,
validate.nameRestrictions,
validate.descriptionRestrictions
validate.positiveInteger('price_cents'),
validate.requiredString('name'),
validate.requiredString('description'),
validate.handleApiError
]
router.post('/', parseJSON, newItemValidators, async (req, res) => {
const errors = validationResult(req)
if(!errors.isEmpty())
return res.status(422).json({errors: errors.array()})
const item = await db.item.create(
req.body.name,
req.body.urlslug,

@ -1,9 +1,9 @@
const {body} = require('express-validator')
const {body, validationResult} = require('express-validator')
const db = require('../../db')
const validators = module.exports = {}
validators.passwordRestrictions = body('password').isString().isLength({min: 8, max: 100}).withMessage('Password must be at least 8 characters')
validators.validPassword = field => body(field).isString().isLength({min: 8, max: 100}).withMessage('Password must be at least 8 characters')
validators.bothPasswordsMatch = body('password').custom((pass, {req})=>{
if(pass !== req.body.password2)
@ -11,26 +11,33 @@ validators.bothPasswordsMatch = body('password').custom((pass, {req})=>{
return true
})
validators.emailRestrictions = body('email').isString().isEmail().withMessage('Email invalid')
validators.validEmail = field => body(field).isString().isEmail()
.withMessage('Email invalid')
validators.checkEmailNotUsed = body('email').custom(async email=>{
const user = await db.user.findByEmail(email)
if(user) throw new Error('Email already in use')
})
validators.unusedEmail = field => validators.validEmail(field)
.custom(async email=>{
const user = await db.user.findByEmail(email)
if(user) throw new Error('Email already in use')
})
validators.urlSlugRestrictions = body('urlslug').isString().isLength({min: 3, max: 20}).matches(/^[-a-z0-9_]*$/i)
validators.validUrlSlug = field => body(field).isString().isLength({min: 3, max: 20}).matches(/^[-a-z0-9_]*$/i)
.withMessage('Slug can be between 3-20 characters long, and can include letters, numbers, dash or underscore')
validators.nameRestrictions = body('name').isString()
.withMessage('Name required. Must be a string')
validators.requiredString = field => body(field).isString()
.withMessage('Required')
validators.descriptionRestrictions = body('description').isString()
.withMessage('Description required. Must be a string')
validators.positiveInteger = field => body(field).isInt().custom(value => value > 0)
.withMessage('Must be a positive integer')
validators.publishedBool = body('published').isBoolean()
validators.priceCentsInt = body('price_cents').isInt().custom(price => price > 0)
.withMessage('Price must be a positive integer')
validators.isUUID = field => body(field).isString().isUUID()
validators.handleApiError = (req, res, next) => {
const errors = validationResult(req)
if(errors.isEmpty())
return next()
validators.countInt = body('count').isInt().custom(count => count > 0)
.withMessage('Count must be a positive integer')
res.status(422).json({errors: errors.array()})
}

@ -2,16 +2,16 @@ const router = require('express-promise-router')()
const parseJSON = require('body-parser').json()
const db = require('../db')
const {validationResult} = require('express-validator')
const validate = require('./middleware/validators')
const registerValidation = [validate.emailRestrictions, validate.passwordRestrictions, validate.bothPasswordsMatch, validate.checkEmailNotUsed]
router.post('/', parseJSON, registerValidation, async (req, res) => {
const errors = validationResult(req)
if(!errors.isEmpty())
return res.status(422).json({errors: errors.array()})
const registerValidation = [
validate.unusedEmail('email'),
validate.validPassword('password'),
validate.bothPasswordsMatch,
validate.handleApiError
]
router.post('/', parseJSON, registerValidation, async (req, res) => {
const user = await db.user.register(
req.body.email,
req.body.password

@ -10,15 +10,15 @@ export default function Table({columns, rows, foot}) {
)}
</tr>
</thead>
<tbody>
{rows && rows.length > 0 && <tbody>
{rows.map(row=>
<tr key={row.id} className={row.class}>
{columns.map(column=>
<td key={column.name}>{column.extractor(row)}</td>
<td key={column.name}>{column.extractor(row)}</td>
)}
</tr>
)}
</tbody>
</tbody>}
{foot && <tfoot>
<tr>
{foot.map((item, i) =>
@ -30,4 +30,4 @@ export default function Table({columns, rows, foot}) {
</tfoot>}
</table>
)
}
}

@ -21,4 +21,4 @@
.table td {
padding: 15px;
}
}

@ -6,6 +6,8 @@ import {FormController, Input, Button} from '~/components/form'
import Table from '~/components/table'
export default function Cart({cart, setCart}){
const numItems = (cart?.items) ? cart.items.length : 0
const handleRemove = id => async ev => {
if(ev) ev.preventDefault()
@ -13,36 +15,55 @@ export default function Cart({cart, setCart}){
setCart(data)
}
const handleCreateTransaction = async () => {
}
return (
<>
<Head><title>Cart</title></Head>
<>
<h2>Cart</h2>
<Table
columns={[
{name: 'Item', extractor: row => row.item.name},
{name: 'Quantity in Cart', extractor: row => row.count},
{name: 'Price Each', extractor: row => '$' + (row.item.price_cents / 100).toFixed(2)},
{name: 'Total Price', extractor: row => '$' + (row.count * row.item.price_cents / 100).toFixed(2)},
{name: '', extractor: row =>
<button className="buttonLink" onClick={handleRemove(row.item.uuid)}>Remove</button>
}
]}
rows={cart?.items?.map(row=>({
...row,
id: row.item.uuid
}))}
foot={[
'Total:',
cart?.items.map(r=>r.count).reduce((a,b) => (a+b), 0) || 0,
'',
'$' + ((cart?.items.map(r=>r.count * r.item.price_cents).reduce((a,b) => (a+b), 0) || 0) / 100).toFixed(2),
''
]}
/>
{
numItems > 0
?<Table
columns={[
{name: 'Item', extractor: row => row.item.name},
{name: 'Quantity in Cart', extractor: row => row.count},
{name: 'Price Each', extractor: row => '$' + (row.item.price_cents / 100).toFixed(2)},
{name: 'Total Price', extractor: row => '$' + (row.count * row.item.price_cents / 100).toFixed(2)},
{name: '', extractor: row =>
<button className="buttonLink" onClick={handleRemove(row.item.uuid)}>Remove</button>
}
]}
rows={cart?.items?.map(row=>({
...row,
id: row.item.uuid
}))}
foot={[
'Total:',
cart?.items.map(r=>r.count).reduce((a,b) => (a+b), 0) || 0,
'',
'$' + ((cart?.items.map(r=>r.count * r.item.price_cents).reduce((a,b) => (a+b), 0) || 0) / 100).toFixed(2),
''
]}
/>
// Empty cart table
:<Table
columns={[
{name: 'No items in cart'}
]}
foot={[
'Total:',
'',
'',
'$0.00'
]}
/>
}
<FormController>
<Input label="Coupon Code" type="text" name="coupon"/>
<Button enabled={!!(cart?.items?.length)} type="submit">Proceed to Checkout</Button>
</FormController>
</>

Loading…
Cancel
Save