fix: data type validation in accounts, users, contacts, vendors, customers, journals.

This commit is contained in:
Ahmed Bouhuolia
2020-11-29 17:51:40 +02:00
parent ba6a29579a
commit a4195069c7
9 changed files with 159 additions and 78 deletions

View File

@@ -7,6 +7,7 @@ import AccountsService from 'services/Accounts/AccountsService';
import { IAccountDTO, IAccountsFilter } from 'interfaces';
import { ServiceError } from 'exceptions';
import DynamicListingService from 'services/DynamicListing/DynamicListService';
import { DATATYPES_LENGTH } from 'data/DataTypes';
@Service()
export default class AccountsController extends BaseController{
@@ -112,7 +113,7 @@ export default class AccountsController extends BaseController{
return [
check('name')
.exists()
.isLength({ min: 3, max: 255 })
.isLength({ min: 3, max: DATATYPES_LENGTH.STRING })
.trim()
.escape(),
check('code')
@@ -122,16 +123,16 @@ export default class AccountsController extends BaseController{
.escape(),
check('account_type_id')
.exists()
.isNumeric()
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('description')
.optional({ nullable: true })
.isLength({ max: 512 })
.isLength({ max: DATATYPES_LENGTH.TEXT })
.trim()
.escape(),
check('parent_account_id')
.optional({ nullable: true })
.isNumeric()
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt(),
];
}

View File

@@ -6,6 +6,7 @@ import asyncMiddleware from 'api/middleware/asyncMiddleware';
import AuthenticationService from 'services/Authentication';
import { ILoginDTO, ISystemUser, IRegisterOTD } from 'interfaces';
import { ServiceError, ServiceErrors } from "exceptions";
import { DATATYPES_LENGTH } from 'data/DataTypes';
@Service()
export default class AuthenticationController extends BaseController{
@@ -60,12 +61,12 @@ export default class AuthenticationController extends BaseController{
*/
get registerSchema(): ValidationChain[] {
return [
check('first_name').exists().trim().escape(),
check('last_name').exists().trim().escape(),
check('email').exists().isEmail().trim().escape(),
check('phone_number').exists().trim().escape(),
check('password').exists().trim().escape(),
check('country').exists().trim().escape(),
check('first_name').exists().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('last_name').exists().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('email').exists().isString().isEmail().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('phone_number').exists().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('password').exists().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('country').exists().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
];
}

View File

@@ -1,5 +1,6 @@
import { check, param, query, body, ValidationChain } from 'express-validator';
import BaseController from "api/controllers/BaseController";
import { DATATYPES_LENGTH } from 'data/DataTypes';
export default class ContactsController extends BaseController {
/**
@@ -7,37 +8,37 @@ export default class ContactsController extends BaseController {
*/
get contactDTOSchema(): ValidationChain[] {
return [
check('salutation').optional().trim().escape(),
check('first_name').optional().trim().escape(),
check('last_name').optional().trim().escape(),
check('salutation').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('first_name').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('last_name').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('company_name').optional().trim().escape(),
check('display_name').exists().trim().escape(),
check('company_name').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('display_name').exists().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('email').optional({ nullable: true }).normalizeEmail().isEmail(),
check('website').optional().trim().isURL(),
check('work_phone').optional().trim().escape(),
check('personal_phone').optional().trim().escape(),
check('email').optional({ nullable: true }).isString().normalizeEmail().isEmail().isLength({ max: DATATYPES_LENGTH.STRING }),
check('website').optional().isString().trim().isURL().isLength({ max: DATATYPES_LENGTH.STRING }),
check('work_phone').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('personal_phone').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_1').optional().trim().escape(),
check('billing_address_2').optional().trim().escape(),
check('billing_address_city').optional().trim().escape(),
check('billing_address_country').optional().trim().escape(),
check('billing_address_email').optional().isEmail().trim().escape(),
check('billing_address_postcode').optional().trim().escape(),
check('billing_address_phone').optional().trim().escape(),
check('billing_address_state').optional().trim().escape(),
check('billing_address_1').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_2').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_city').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_country').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_email').optional().isString().isEmail().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_postcode').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_phone').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('billing_address_state').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_1').optional().trim().escape(),
check('shipping_address_2').optional().trim().escape(),
check('shipping_address_city').optional().trim().escape(),
check('shipping_address_country').optional().trim().escape(),
check('shipping_address_email').optional().isEmail().trim().escape(),
check('shipping_address_postcode').optional().trim().escape(),
check('shipping_address_phone').optional().trim().escape(),
check('shipping_address_state').optional().trim().escape(),
check('shipping_address_1').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_2').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_city').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_country').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_email').optional().isString().isEmail().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_postcode').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_phone').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('shipping_address_state').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.STRING }),
check('note').optional().trim().escape(),
check('note').optional().isString().trim().escape().isLength({ max: DATATYPES_LENGTH.TEXT }),
check('active').optional().isBoolean().toBoolean(),
];
}
@@ -48,8 +49,10 @@ export default class ContactsController extends BaseController {
*/
get contactNewDTOSchema(): ValidationChain[] {
return [
check('opening_balance').optional({ nullable: true }).isNumeric().toInt(),
body('opening_balance_at').if(body('opening_balance').exists()).exists(),
check('opening_balance').optional({ nullable: true }).isInt({ min: 0, max: DATATYPES_LENGTH.DECIMAL_13_3 }).toInt(),
body('opening_balance_at')
.if(body('opening_balance').exists()).exists()
.isISO8601(),
];
}

View File

@@ -90,7 +90,7 @@ export default class CustomersController extends ContactsController {
*/
get createCustomerDTOSchema() {
return [
check('currency_code').optional().trim().escape(),
check('currency_code').optional().isString().trim().escape().isLength({ max: 3, min: 3 }),
];
}

View File

@@ -73,7 +73,12 @@ export default class VendorsController extends ContactsController {
*/
get vendorDTOSchema(): ValidationChain[] {
return [
check('currency_code').optional().trim().escape(),
check('currency_code')
.optional()
.isString()
.trim()
.escape()
.isLength({ min: 3, max: 3 }),
];
}

View File

@@ -11,6 +11,7 @@ import { IItemCategoryOTD } from 'interfaces';
import { ServiceError } from 'exceptions';
import BaseController from 'api/controllers/BaseController';
import DynamicListingService from 'services/DynamicListing/DynamicListService';
import { DATATYPES_LENGTH } from 'data/DataTypes';
@Service()
export default class ItemsCategoriesController extends BaseController {
@@ -78,26 +79,32 @@ export default class ItemsCategoriesController extends BaseController {
*/
get categoryValidationSchema() {
return [
check('name').exists().trim().escape(),
check('name')
.exists()
.trim()
.escape()
.isLength({ min: 0, max: DATATYPES_LENGTH.STRING }),
check('parent_category_id')
.optional({ nullable: true })
.isNumeric()
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('description')
.optional()
.isString()
.trim()
.escape(),
.escape()
.isLength({ max: DATATYPES_LENGTH.TEXT }),
check('sell_account_id')
.optional({ nullable: true })
.isNumeric()
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('cost_account_id')
.optional({ nullable: true })
.isNumeric()
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('inventory_account_id')
.optional({ nullable: true })
.isNumeric()
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt(),
]
}

View File

@@ -7,6 +7,7 @@ import BaseController from 'api/controllers/BaseController';
import DynamicListingService from 'services/DynamicListing/DynamicListService';
import { ServiceError } from 'exceptions';
import { IItemDTO } from 'interfaces';
import { DATATYPES_LENGTH } from 'data/DataTypes';
@Service()
export default class ItemsController extends BaseController {
@@ -78,44 +79,74 @@ export default class ItemsController extends BaseController {
*/
get validateItemSchema(): ValidationChain[] {
return [
check('name').exists(),
check('type').exists().trim().escape()
check('name').exists().isString().isLength({ max: DATATYPES_LENGTH.STRING }),
check('type').exists()
.isString()
.trim()
.escape()
.isIn(['service', 'non-inventory', 'inventory']),
check('code').optional({ nullable: true }).trim().escape(),
check('code')
.optional({ nullable: true })
.isString()
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.STRING }),
// Purchase attributes.
check('purchasable').optional().isBoolean().toBoolean(),
check('cost_price')
.optional({ nullable: true })
.isFloat({ min: 0, max: DATATYPES_LENGTH.DECIMAL_13_3 })
.toFloat()
.if(check('purchasable').equals('true'))
.exists()
.isNumeric()
.toFloat(),
.exists(),
check('cost_account_id')
.optional({ nullable: true })
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt()
.if(check('purchasable').equals('true'))
.exists()
.isInt()
.toInt(),
.exists(),
// Sell attributes.
check('sellable').optional().isBoolean().toBoolean(),
check('sell_price')
.optional({ nullable: true })
.isFloat({ min: 0, max: DATATYPES_LENGTH.DECIMAL_13_3 })
.toFloat()
.if(check('sellable').equals('true'))
.exists()
.isNumeric()
.toFloat(),
.exists(),
check('sell_account_id')
.optional({ nullable: true })
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt()
.if(check('sellable').equals('true'))
.exists()
.isInt()
.toInt(),
.exists(),
check('inventory_account_id')
.optional({ nullable: true })
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt()
.if(check('type').equals('inventory'))
.exists()
.isInt()
.exists(),
check('sell_description')
.optional({ nullable: true })
.isString()
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.TEXT }),
check('cost_description')
.optional({ nullable: true })
.isString()
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.TEXT }),
check('category_id')
.optional({ nullable: true })
.isInt({ min: 0, max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('sell_description').optional({ nullable: true }).trim().escape(),
check('cost_description').optional({ nullable: true }).trim().escape(),
check('category_id').optional({ nullable: true }).isInt().toInt(),
check('note').optional(),
check('note')
.optional()
.isString()
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.TEXT }),
check('active').optional().isBoolean().toBoolean(),
check('media_ids').optional().isArray(),

View File

@@ -6,6 +6,7 @@ import ManualJournalsService from 'services/ManualJournals/ManualJournalsService
import { Inject, Service } from "typedi";
import { ServiceError } from 'exceptions';
import DynamicListingService from 'services/DynamicListing/DynamicListService';
import { DATATYPES_LENGTH } from 'data/DataTypes';
@Service()
export default class ManualJournalsController extends BaseController {
@@ -113,30 +114,54 @@ export default class ManualJournalsController extends BaseController {
get manualJournalValidationSchema() {
return [
check('date').exists().isISO8601(),
check('journal_number').exists().trim().escape(),
check('journal_type').optional({ nullable: true }).trim().escape(),
check('reference').optional({ nullable: true }),
check('description').optional().trim().escape(),
check('journal_number')
.exists()
.isString()
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.STRING }),
check('journal_type')
.optional({ nullable: true })
.isString()
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.STRING }),
check('reference')
.optional({ nullable: true })
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.STRING }),
check('description')
.optional()
.isString()
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.TEXT }),
check('status').optional().isBoolean().toBoolean(),
check('entries').isArray({ min: 2 }),
check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.index')
.exists()
.isInt({ max: DATATYPES_LENGTH.INT_10 }).toInt(),
check('entries.*.credit')
.optional({ nullable: true })
.isNumeric()
.isDecimal()
.isFloat({ max: 9999999999.999 }) // 13, 3
.isFloat({ max: DATATYPES_LENGTH.INT_13_3 }) // 13, 3
.toFloat(),
check('entries.*.debit')
.optional({ nullable: true })
.isNumeric()
.isDecimal()
.isFloat({ max: 9999999999.999 }) // 13, 3
.isFloat({ max: DATATYPES_LENGTH.INT_13_3 }) // 13, 3
.toFloat(),
check('entries.*.account_id').isNumeric().toInt(),
check('entries.*.note').optional(),
check('entries.*.account_id').isInt({ max: DATATYPES_LENGTH.INT_10 }).toInt(),
check('entries.*.note')
.optional()
.isString()
.isLength({ max: DATATYPES_LENGTH.STRING }),
check('entries.*.contact_id')
.optional({ nullable: true })
.isNumeric()
.isInt({ max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('entries.*.contact_type').optional().isIn(['vendor', 'customer']),
]