diff --git a/restfulpy/tests/test_validation.py b/restfulpy/tests/test_validation.py deleted file mode 100644 index 296bda9..0000000 --- a/restfulpy/tests/test_validation.py +++ /dev/null @@ -1,637 +0,0 @@ -import copy -import unittest - -from nanohttp import context, json, settings - -from restfulpy.principal import DummyIdentity -from restfulpy.testing import WebAppTestCase -from restfulpy.tests.helpers import MockupApplication -from restfulpy.validation import validate_form -from restfulpy.controllers import RestController, RootController - - -class ValidationController(RestController): - @json - @validate_form(blacklist=['blacklistParamForAll'], - client={'blacklist': ['blacklistParamForClient']}, - admin={'blacklist': ['blacklistParamForAdmin']}) - def test_blacklist(self): - result = copy.deepcopy(context.form) - result.update(context.query_string) - return result - - @json - @validate_form(exclude=['excludedParamForAll'], - client={'exclude': ['excludedParamForClient']}, - admin={'exclude': ['excludedParamForAdmin']}) - def test_exclude(self): - result = copy.deepcopy(context.form) - result.update(context.query_string) - return result - - @json - @validate_form( - filter_=['filteredParamForAll'], - client=dict(filter_=['filteredParamForClient']), - admin=dict(filter_=['filteredParamForAdmin']) - ) - def test_filter(self): - result = copy.deepcopy(context.form) - result.update(context.query_string) - return result - - @json - @validate_form(whitelist=['whitelistParamForAll'], - client={'whitelist': ['whitelistParamForClient']}, - admin={'whitelist': ['whitelistParamForAdmin']}) - def test_whitelist(self): - result = copy.deepcopy(context.form) - result.update(context.query_string) - return result - - @json - @validate_form(requires=['requiresParamForAll'], - client={'requires': ['requiresParamForClient']}, - admin={'requires': ['requiresParamForAdmin']}) - def test_requires(self): - result = copy.deepcopy(context.form) - result.update(context.query_string) - return result - - @json - @validate_form(exact=['exactParamForAll'], - client={'exact': ['exactParamForClient']}, - admin={'exact': ['exactParamForAdmin']}) - def test_exact(self): - result = copy.deepcopy(context.form) - result.update(context.query_string) - return result - - @json - @validate_form( - types={ - 'typedParam1': float, - 'typedParam2': float, - 'typedParam3': float, - }, - client={ - 'types': { - 'typedParam1': int, - 'typedParam2': int - } - }, - admin={ - 'types': { - 'typedParam1': complex, - 'typedParam4': complex - } - } - ) - def test_type(self): - result = copy.deepcopy(context.form) - result.update(context.query_string) - return result - - -class Root(RootController): - validation = ValidationController() - - -class ValidationTestCase(WebAppTestCase): - application = MockupApplication('MockupApplication', Root()) - - @classmethod - def configure_app(cls): - super().configure_app() - settings.merge(""" - logging: - loggers: - default: - level: info - """) - - def test_validation_blacklist(self): - # Test `blacklist` - # role -> All - self.wsgi_app.jwt_token = DummyIdentity().dump().decode() - self.request('All', 'TEST_BLACKLIST', '/validation', doc=False) - self.request('All', 'TEST_BLACKLIST', '/validation', doc=False, params={'customParam': 'param'}) - self.request('All', 'TEST_BLACKLIST', '/validation', doc=False, params={'blacklistParamForAll': 'param'}, - expected_status=400) - self.request('All', 'TEST_BLACKLIST', '/validation', doc=False, params={'blacklistParamForClient': 'param'}) - self.request('All', 'TEST_BLACKLIST', '/validation', doc=False, params={'blacklistParamForAdmin': 'param'}) - # ----------------------------- - # role -> Client - self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() - self.request('Client', 'TEST_BLACKLIST', '/validation', doc=False) - self.request('Client', 'TEST_BLACKLIST', '/validation', doc=False, params={'customParam': 'param'}) - self.request('Client', 'TEST_BLACKLIST', '/validation', doc=False, params={'blacklistParamForAll': 'param'}, - expected_status=400) - self.request( - 'Client', 'TEST_BLACKLIST', '/validation', doc=False, - params={'blacklistParamForClient': 'param'}, - expected_status=400 - ) - self.request('Client', 'TEST_BLACKLIST', '/validation', doc=False, params={ - 'blacklistParamForAdmin': 'param' - }) - # ----------------------------- - # role -> Admin - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - self.request('Admin', 'TEST_BLACKLIST', '/validation', doc=False) - self.request('Admin', 'TEST_BLACKLIST', '/validation', doc=False, params={'customParam': 'param'}) - self.request('Admin', 'TEST_BLACKLIST', '/validation', doc=False, params={'blacklistParamForAll': 'param'}, - expected_status=400) - self.request('Admin', 'TEST_BLACKLIST', '/validation', doc=False, params={'blacklistParamForClient': 'param'}) - self.request('Admin', 'TEST_BLACKLIST', '/validation', doc=False, params={'blacklistParamForAdmin': 'param'}, - expected_status=400) - - def test_validation_exclude(self): - # Test `exclude` - # role -> All - self.wsgi_app.jwt_token = DummyIdentity().dump().decode() - result, ___ = self.request( - 'All', 'TEST_EXCLUDE', '/validation', doc=False, - params={ - 'customParam': 'param', - 'excludedParamForAll': 'param', - 'excludedParamForClient': 'param', - 'excludedParamForAdmin': 'param', - } - ) - self.assertIn('customParam', result) - self.assertIn('excludedParamForClient', result) - self.assertIn('excludedParamForAdmin', result) - self.assertNotIn('excludedParamForAll', result) - # ----------------------------- - # role -> Client - self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() - result, ___ = self.request( - 'Client', 'TEST_EXCLUDE', '/validation', doc=False, - params={ - 'customParam': 'param', - 'excludedParamForAll': 'param', - 'excludedParamForClient': 'param', - 'excludedParamForAdmin': 'param', - } - ) - self.assertIn('customParam', result) - self.assertNotIn('excludedParamForClient', result) - self.assertIn('excludedParamForAdmin', result) - self.assertNotIn('excludedParamForAll', result) - # ----------------------------- - # role -> Admin - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - result, ___ = self.request( - 'Admin', 'TEST_EXCLUDE', '/validation', doc=False, - params={ - 'customParam': 'param', - 'excludedParamForAll': 'param', - 'excludedParamForClient': 'param', - 'excludedParamForAdmin': 'param', - } - ) - self.assertIn('customParam', result) - self.assertIn('excludedParamForClient', result) - self.assertNotIn('excludedParamForAdmin', result) - self.assertNotIn('excludedParamForAll', result) - - def test_validation_filter(self): - # Test `filter` - # role -> All - self.wsgi_app.jwt_token = DummyIdentity().dump().decode() - result, ___ = self.request( - 'All', 'TEST_FILTER', '/validation', doc=False, - params={ - 'customParam': 'param', - 'filteredParamForAll': 'param', - 'filteredParamForClient': 'param', - 'filteredParamForAdmin': 'param', - } - ) - self.assertNotIn('customParam', result) - self.assertNotIn('filteredParamForClient', result) - self.assertNotIn('filteredParamForAdmin', result) - self.assertIn('filteredParamForAll', result) - # ----------------------------- - # role -> Client - self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() - result, ___ = self.request( - 'Client', 'TEST_FILTER', '/validation', doc=False, - params={ - 'customParam': 'param', - 'filteredParamForAll': 'param', - 'filteredParamForClient': 'param', - 'filteredParamForAdmin': 'param', - } - ) - self.assertNotIn('customParam', result) - self.assertIn('filteredParamForClient', result) - self.assertNotIn('filteredParamForAdmin', result) - self.assertIn('filteredParamForAll', result) - # ----------------------------- - # role -> Admin - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - result, ___ = self.request( - 'Admin', 'TEST_FILTER', '/validation', doc=False, - params={ - 'customParam': 'param', - 'filteredParamForAll': 'param', - 'filteredParamForClient': 'param', - 'filteredParamForAdmin': 'param', - } - ) - self.assertNotIn('customParam', result) - self.assertNotIn('filteredParamForClient', result) - self.assertIn('filteredParamForAdmin', result) - self.assertIn('filteredParamForAll', result) - - def test_validation_whitelist(self): - # Test `whitelist` - # role -> All - self.wsgi_app.jwt_token = DummyIdentity().dump().decode() - result, ___ = self.request('All', 'TEST_WHITELIST', '/validation', doc=False, - params={'whitelistParamForAll': 'param'}) - self.assertIn('whitelistParamForAll', result) - self.request('All', 'TEST_WHITELIST', '/validation', doc=False) - self.request( - 'All', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'whitelistParamForAll': 'param', - 'customParam': 'param' - }, - expected_status=400 - ) - self.request('All', 'TEST_WHITELIST', '/validation', doc=False, params={'customParam': 'param'}, - expected_status=400) - self.request('All', 'TEST_WHITELIST', '/validation', doc=False, params={'whitelistParamForClient': 'param', }, - expected_status=400) - # ----------------------------- - # role -> Client - self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() - - result, ___ = self.request('Client', 'TEST_WHITELIST', '/validation', doc=False, - params={'whitelistParamForAll': 'param'}) - self.assertIn('whitelistParamForAll', result) - - result, ___ = self.request('Client', 'TEST_WHITELIST', '/validation', doc=False, - params={'whitelistParamForClient': 'param'}) - self.assertIn('whitelistParamForClient', result) - - result, ___ = self.request( - 'Client', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'whitelistParamForAll': 'param', - 'whitelistParamForClient': 'param', - } - ) - self.assertIn('whitelistParamForAll', result) - self.assertIn('whitelistParamForClient', result) - - self.request('Client', 'TEST_WHITELIST', '/validation', doc=False) - - self.request( - 'Client', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'whitelistParamForAll': 'param', - 'customParam': 'param', - }, - expected_status=400 - ) - - self.request( - 'Client', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'customParam': 'param', - }, - expected_status=400 - ) - - self.request( - 'Client', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'whitelistParamForAdmin': 'param', - }, - expected_status=400 - ) - - # ----------------------------- - # role -> Admin - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - - result, ___ = self.request('Admin', 'TEST_WHITELIST', '/validation', doc=False, - params={'whitelistParamForAll': 'param'}) - self.assertIn('whitelistParamForAll', result) - - result, ___ = self.request('Admin', 'TEST_WHITELIST', '/validation', doc=False, - params={'whitelistParamForAdmin': 'param'}) - self.assertIn('whitelistParamForAdmin', result) - - result, ___ = self.request( - 'Admin', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'whitelistParamForAll': 'param', - 'whitelistParamForAdmin': 'param', - } - ) - self.assertIn('whitelistParamForAll', result) - self.assertIn('whitelistParamForAdmin', result) - - self.request('Admin', 'TEST_WHITELIST', '/validation', doc=False) - - self.request( - 'Admin', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'whitelistParamForAll': 'param', - 'customParam': 'param', - }, - expected_status=400 - ) - - self.request('Admin', 'TEST_WHITELIST', '/validation', doc=False, params={ - 'customParam': 'param', - }, expected_status=400) - - self.request( - 'Admin', 'TEST_WHITELIST', '/validation', doc=False, - params={ - 'whitelistParamForAll': 'param', - 'whitelistParamForAdmin': 'param', - 'whitelistParamForClient': 'param', - }, - expected_status=400 - ) - - def test_validation_requires(self): - # Test `requires` - # role -> All - self.wsgi_app.jwt_token = DummyIdentity().dump().decode() - - result, ___ = self.request('All', 'TEST_REQUIRES', '/validation', doc=False, - params={'requiresParamForAll': 'param'}) - self.assertIn('requiresParamForAll', result) - - result, ___ = self.request( - 'All', 'TEST_REQUIRES', '/validation', doc=False, - params={ - 'customParam': 'param', - 'requiresParamForAll': 'param', - } - ) - self.assertIn('customParam', result) - self.assertIn('requiresParamForAll', result) - - self.request('All', 'TEST_REQUIRES', '/validation', doc=False, expected_status=400) - - self.request('All', 'TEST_REQUIRES', '/validation', doc=False, params={'customParam': 'param'}, - expected_status=400) - - self.request('All', 'TEST_REQUIRES', '/validation', doc=False, params={'requiresParamForClient': 'param'}, - expected_status=400) - - # ----------------------------- - # role -> Client - self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() - result, ___ = self.request( - 'Client', 'TEST_REQUIRES', '/validation', doc=False, - params={ - 'requiresParamForAll': 'param', - 'requiresParamForClient': 'param', - } - ) - self.assertIn('requiresParamForAll', result) - self.assertIn('requiresParamForClient', result) - - result, ___ = self.request( - 'Client', 'TEST_REQUIRES', '/validation', doc=False, - params={ - 'customParam': 'param', - 'requiresParamForAll': 'param', - 'requiresParamForClient': 'param', - } - ) - self.assertIn('customParam', result) - self.assertIn('requiresParamForAll', result) - self.assertIn('requiresParamForClient', result) - - self.request('Client', 'TEST_REQUIRES', '/validation', doc=False, expected_status=400) - - self.request('Client', 'TEST_REQUIRES', '/validation', doc=False, params={'customParam': 'param'}, - expected_status=400) - - self.request('Client', 'TEST_REQUIRES', '/validation', doc=False, params={'requiresParamForAll': 'param'}, - expected_status=400) - - self.request('Client', 'TEST_REQUIRES', '/validation', doc=False, params={ - 'requiresParamForClient': - 'param', - }, expected_status=400) - # ----------------------------- - # role -> Admin - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - result, ___ = self.request('Admin', 'TEST_REQUIRES', '/validation', doc=False, params={ - 'requiresParamForAll': 'param', - 'requiresParamForAdmin': 'param', - }) - self.assertIn('requiresParamForAll', result) - self.assertIn('requiresParamForAdmin', result) - result, ___ = self.request( - 'Admin', 'TEST_REQUIRES', '/validation', doc=False, - params={ - 'customParam': 'param', - 'requiresParamForAll': 'param', - 'requiresParamForAdmin': 'param', - } - ) - self.assertIn('customParam', result) - self.assertIn('requiresParamForAll', result) - self.assertIn('requiresParamForAdmin', result) - - self.request('Admin', 'TEST_REQUIRES', '/validation', doc=False, expected_status=400) - - self.request('Admin', 'TEST_REQUIRES', '/validation', doc=False, params={'customParam': 'param'}, - expected_status=400) - - self.request( - 'Admin', 'TEST_REQUIRES', '/validation', doc=False, - params={ - 'requiresParamForAll': 'param', - 'requiresParamForClient': 'param', - }, - expected_status=400 - ) - - self.request('Admin', 'TEST_REQUIRES', '/validation', doc=False, params={'requiresParamForAdmin': 'param'}, - expected_status=400) - - def test_validation_exact(self): - # Test `exact` - # role -> All - self.wsgi_app.jwt_token = DummyIdentity().dump().decode() - result, ___ = self.request('All', 'TEST_EXACT', '/validation', doc=False, params={'exactParamForAll': 'param'}) - self.request('All', 'TEST_EXACT', '/validation', doc=False, expected_status=400) - self.request( - 'All', 'TEST_EXACT', '/validation', doc=False, - params={ - 'exactParamForAll': 'param', - 'exactParamForCustom': 'param', - }, - expected_status=400 - ) - self.request('All', 'TEST_EXACT', '/validation', doc=False, params={'exactParamForCustom': 'param'}, - expected_status=400) - self.assertIn('exactParamForAll', result) - self.request( - 'All', 'TEST_EXACT', '/validation', doc=False, - params={ - 'exactParamForAll': 'param', - 'exactParamForClient': 'param', - }, - expected_status=400 - ) - # ----------------------------- - # role -> Client - self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() - - result, ___ = self.request( - 'Client', 'TEST_EXACT', '/validation', doc=False, - params={ - 'exactParamForAll': 'param', - 'exactParamForClient': 'param', - } - ) - self.assertIn('exactParamForClient', result) - self.assertIn('exactParamForAll', result) - - self.request( - 'Client', 'TEST_EXACT', '/validation', doc=False, - params={ - 'exactParamForAll': 'param', - 'exactParamForClient': 'param', - 'exactParamForAdmin': 'param', - }, - expected_status=400 - ) - - # ----------------------------- - # role -> Admin - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - - result, ___ = self.request('Admin', 'TEST_EXACT', '/validation', doc=False, params={ - 'exactParamForAll': 'param', - 'exactParamForAdmin': 'param', - }) - self.assertIn('exactParamForAdmin', result) - self.assertIn('exactParamForAll', result) - - self.request('Admin', 'TEST_EXACT', '/validation', doc=False, params={ - 'exactParamForAll': 'param', - 'exactParamForClient': 'param', - 'exactParamForAdmin': 'param', - }, expected_status=400) - - # ------------------------------------------------------------ - - # Test query string - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - result, ___ = self.request( - 'Admin', 'TEST_EXACT', '/validation', doc=False, - query_string={ - 'exactParamForAll': 'param', - }, - params={ - 'exactParamForAdmin': 'param', - } - ) - self.assertIn('exactParamForAdmin', result) - self.assertIn('exactParamForAll', result) - - self.request( - 'Admin', 'TEST_EXACT', '/validation', doc=False, - query_string={ - 'exactParamForAll': 'param', - 'exactParamForClient': 'param', - }, - params={'exactParamForAdmin': 'param'}, expected_status=400 - ) - - def test_validation_types(self): - # Test `type` - # role -> All - self.wsgi_app.jwt_token = DummyIdentity().dump().decode() - result, ___ = self.request( - 'All', 'TEST_TYPE', '/validation', - doc=False, - params={ - 'typedParam1': '1', - 'typedParam2': '2', - 'typedParam3': '3', - 'typedParam4': '4' - } - ) - self.assertEqual(type(result['typedParam1']), float) - self.assertEqual(type(result['typedParam2']), float) - self.assertEqual(type(result['typedParam3']), float) - self.assertEqual(type(result['typedParam4']), str) - - self.request( - 'All', 'TEST_TYPE', '/validation', - doc=False, - params={'typedParam1': 'not_convertible'}, - expected_status=400 - ) - - # ----------------------------- - # role -> Client - self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() - result, ___ = self.request( - 'Client', 'TEST_TYPE', '/validation', - doc=False, - params={ - 'typedParam1': '1', - 'typedParam2': '2', - 'typedParam3': '3', - 'typedParam4': '4' - } - ) - self.assertEqual(type(result['typedParam1']), int) - self.assertEqual(type(result['typedParam2']), int) - self.assertEqual(type(result['typedParam3']), float) - self.assertEqual(type(result['typedParam4']), str) - - self.request( - 'Client', 'TEST_TYPE', '/validation', - doc=False, - params={'typedParam1': 'not_convertible'}, - expected_status=400 - ) - - # ----------------------------- - # role -> Admin - self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() - result, ___ = self.request( - 'Admin', 'TEST_TYPE', '/validation', - doc=False, - params={ - 'typedParam1': '1', - 'typedParam2': '2', - 'typedParam3': '3', - 'typedParam4': '4' - } - ) - # type complex is dict - self.assertEqual(type(result['typedParam1']), dict) - self.assertEqual(type(result['typedParam2']), float) - self.assertEqual(type(result['typedParam3']), float) - self.assertEqual(type(result['typedParam4']), dict) - - self.request( - 'Admin', 'TEST_TYPE', '/validation', - doc=False, - params={'typedParam1': 'not_convertible'}, - expected_status=400 - ) - - -if __name__ == '__main__': # pragma: no cover - unittest.main() diff --git a/restfulpy/tests/test_validation_blacklist.py b/restfulpy/tests/test_validation_blacklist.py new file mode 100644 index 0000000..5976924 --- /dev/null +++ b/restfulpy/tests/test_validation_blacklist.py @@ -0,0 +1,79 @@ +import copy +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationBlackListController(RestController): + @json + @validate_form(blacklist=['blacklistParamForAll'], + client={'blacklist': ['blacklistParamForClient']}, + admin={'blacklist': ['blacklistParamForAdmin']}) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationBlackListController() + + +class ValidationBlackListTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_blacklist(self): + # Test `blacklist` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + self.request('All', 'POST', '/validation', doc=False) + self.request('All', 'POST', '/validation', doc=False, params={'customParam': 'param'}) + self.request('All', 'POST', '/validation', doc=False, params={'blacklistParamForAll': 'param'}, + expected_status=400) + self.request('All', 'POST', '/validation', doc=False, params={'blacklistParamForClient': 'param'}) + self.request('All', 'POST', '/validation', doc=False, params={'blacklistParamForAdmin': 'param'}) + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + self.request('Client', 'POST', '/validation', doc=False) + self.request('Client', 'POST', '/validation', doc=False, params={'customParam': 'param'}) + self.request('Client', 'POST', '/validation', doc=False, params={'blacklistParamForAll': 'param'}, + expected_status=400) + self.request( + 'Client', 'POST', '/validation', doc=False, + params={'blacklistParamForClient': 'param'}, + expected_status=400 + ) + self.request('Client', 'POST', '/validation', doc=False, params={ + 'blacklistParamForAdmin': 'param' + }) + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + self.request('Admin', 'POST', '/validation', doc=False) + self.request('Admin', 'POST', '/validation', doc=False, params={'customParam': 'param'}) + self.request('Admin', 'POST', '/validation', doc=False, params={'blacklistParamForAll': 'param'}, + expected_status=400) + self.request('Admin', 'POST', '/validation', doc=False, params={'blacklistParamForClient': 'param'}) + self.request('Admin', 'POST', '/validation', doc=False, params={'blacklistParamForAdmin': 'param'}, + expected_status=400) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/tests/test_validation_exact.py b/restfulpy/tests/test_validation_exact.py new file mode 100644 index 0000000..ada545f --- /dev/null +++ b/restfulpy/tests/test_validation_exact.py @@ -0,0 +1,135 @@ +import copy +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationController(RestController): + + @json + @validate_form(exact=['exactParamForAll'], + client={'exact': ['exactParamForClient']}, + admin={'exact': ['exactParamForAdmin']}) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationController() + + +class ValidationExactTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_exact(self): + # Test `exact` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + result, ___ = self.request('All', 'POST', '/validation', doc=False, params={'exactParamForAll': 'param'}) + self.request('All', 'POST', '/validation', doc=False, expected_status=400) + self.request( + 'All', 'POST', '/validation', doc=False, + params={ + 'exactParamForAll': 'param', + 'exactParamForCustom': 'param', + }, + expected_status=400 + ) + self.request('All', 'POST', '/validation', doc=False, params={'exactParamForCustom': 'param'}, + expected_status=400) + self.assertIn('exactParamForAll', result) + self.request( + 'All', 'POST', '/validation', doc=False, + params={ + 'exactParamForAll': 'param', + 'exactParamForClient': 'param', + }, + expected_status=400 + ) + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + + result, ___ = self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'exactParamForAll': 'param', + 'exactParamForClient': 'param', + } + ) + self.assertIn('exactParamForClient', result) + self.assertIn('exactParamForAll', result) + + self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'exactParamForAll': 'param', + 'exactParamForClient': 'param', + 'exactParamForAdmin': 'param', + }, + expected_status=400 + ) + + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + + result, ___ = self.request('Admin', 'POST', '/validation', doc=False, params={ + 'exactParamForAll': 'param', + 'exactParamForAdmin': 'param', + }) + self.assertIn('exactParamForAdmin', result) + self.assertIn('exactParamForAll', result) + + self.request('Admin', 'POST', '/validation', doc=False, params={ + 'exactParamForAll': 'param', + 'exactParamForClient': 'param', + 'exactParamForAdmin': 'param', + }, expected_status=400) + + # ------------------------------------------------------------ + + # Test query string + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + result, ___ = self.request( + 'Admin', 'POST', '/validation', doc=False, + query_string={ + 'exactParamForAll': 'param', + }, + params={ + 'exactParamForAdmin': 'param', + } + ) + self.assertIn('exactParamForAdmin', result) + self.assertIn('exactParamForAll', result) + + self.request( + 'Admin', 'POST', '/validation', doc=False, + query_string={ + 'exactParamForAll': 'param', + 'exactParamForClient': 'param', + }, + params={'exactParamForAdmin': 'param'}, expected_status=400 + ) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/tests/test_validation_exclude.py b/restfulpy/tests/test_validation_exclude.py new file mode 100644 index 0000000..5ffd0c3 --- /dev/null +++ b/restfulpy/tests/test_validation_exclude.py @@ -0,0 +1,94 @@ +import copy +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationExcludeController(RestController): + + @json + @validate_form(exclude=['excludedParamForAll'], + client={'exclude': ['excludedParamForClient']}, + admin={'exclude': ['excludedParamForAdmin']}) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationExcludeController() + + +class ValidationExcludeTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_exclude(self): + # Test `exclude` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + result, ___ = self.request( + 'All', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'excludedParamForAll': 'param', + 'excludedParamForClient': 'param', + 'excludedParamForAdmin': 'param', + } + ) + self.assertIn('customParam', result) + self.assertIn('excludedParamForClient', result) + self.assertIn('excludedParamForAdmin', result) + self.assertNotIn('excludedParamForAll', result) + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + result, ___ = self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'excludedParamForAll': 'param', + 'excludedParamForClient': 'param', + 'excludedParamForAdmin': 'param', + } + ) + self.assertIn('customParam', result) + self.assertNotIn('excludedParamForClient', result) + self.assertIn('excludedParamForAdmin', result) + self.assertNotIn('excludedParamForAll', result) + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + result, ___ = self.request( + 'Admin', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'excludedParamForAll': 'param', + 'excludedParamForClient': 'param', + 'excludedParamForAdmin': 'param', + } + ) + self.assertIn('customParam', result) + self.assertIn('excludedParamForClient', result) + self.assertNotIn('excludedParamForAdmin', result) + self.assertNotIn('excludedParamForAll', result) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/tests/test_validation_filter.py b/restfulpy/tests/test_validation_filter.py new file mode 100644 index 0000000..2406552 --- /dev/null +++ b/restfulpy/tests/test_validation_filter.py @@ -0,0 +1,96 @@ +import copy +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationFilterController(RestController): + + @json + @validate_form( + filter_=['filteredParamForAll'], + client=dict(filter_=['filteredParamForClient']), + admin=dict(filter_=['filteredParamForAdmin']) + ) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationFilterController() + + +class ValidationFilterTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_filter(self): + # Test `filter` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + result, ___ = self.request( + 'All', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'filteredParamForAll': 'param', + 'filteredParamForClient': 'param', + 'filteredParamForAdmin': 'param', + } + ) + self.assertNotIn('customParam', result) + self.assertNotIn('filteredParamForClient', result) + self.assertNotIn('filteredParamForAdmin', result) + self.assertIn('filteredParamForAll', result) + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + result, ___ = self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'filteredParamForAll': 'param', + 'filteredParamForClient': 'param', + 'filteredParamForAdmin': 'param', + } + ) + self.assertNotIn('customParam', result) + self.assertIn('filteredParamForClient', result) + self.assertNotIn('filteredParamForAdmin', result) + self.assertIn('filteredParamForAll', result) + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + result, ___ = self.request( + 'Admin', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'filteredParamForAll': 'param', + 'filteredParamForClient': 'param', + 'filteredParamForAdmin': 'param', + } + ) + self.assertNotIn('customParam', result) + self.assertNotIn('filteredParamForClient', result) + self.assertIn('filteredParamForAdmin', result) + self.assertIn('filteredParamForAll', result) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/tests/test_validation_pattern.py b/restfulpy/tests/test_validation_pattern.py new file mode 100644 index 0000000..67b9eb1 --- /dev/null +++ b/restfulpy/tests/test_validation_pattern.py @@ -0,0 +1,123 @@ +import copy +import re +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationPatternController(RestController): + + @json + @validate_form( + pattern={ + 'patternedParam1': re.compile(r'^\d{10}$'), + 'patternedParam2': '^\D{10}$', + 'patternedParam3': re.compile(r'^Exact$'), + }, + client={ + 'pattern': { + 'patternedParam1': re.compile(r'^\d{5}$'), + 'patternedParam2': re.compile(r'^\D{5}$') + } + }, + admin={ + 'pattern': { + 'patternedParam1': '^\d+$', + 'patternedParam4': re.compile(r'^SuperAdmin$') + } + } + ) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationPatternController() + + +class ValidationPatternTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_pattern(self): + # Test `pattern` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + self.request( + 'All', 'POST', '/validation', + doc=False, + params={ + 'patternedParam1': '0123456789', + 'patternedParam2': 'abcdeFGHIJ', + 'patternedParam3': 'Exact' + } + ) + + self.request( + 'All', 'POST', '/validation', + doc=False, + params={'patternedParam1': '12345'}, + expected_status=400 + ) + + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + self.request( + 'Client', 'POST', '/validation', + doc=False, + params={ + 'patternedParam1': '12345', + 'patternedParam2': 'ABCDE', + 'patternedParam3': 'Exact', + 'patternedParam4': 'anything' + } + ) + + self.request( + 'Client', 'POST', '/validation', + doc=False, + params={'patternedParam1': '1'}, + expected_status=400 + ) + + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + self.request( + 'Admin', 'POST', '/validation', + doc=False, + params={ + 'patternedParam1': '1', + 'patternedParam2': 'ABCDEFGHIJ', + 'patternedParam4': 'SuperAdmin' + } + ) + + self.request( + 'Admin', 'POST', '/validation', + doc=False, + params={'patternedParam4': 'anything'}, + expected_status=400 + ) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/tests/test_validation_requires.py b/restfulpy/tests/test_validation_requires.py new file mode 100644 index 0000000..6a7db3a --- /dev/null +++ b/restfulpy/tests/test_validation_requires.py @@ -0,0 +1,146 @@ +import copy +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationRequiresController(RestController): + + @json + @validate_form(requires=['requiresParamForAll'], + client={'requires': ['requiresParamForClient']}, + admin={'requires': ['requiresParamForAdmin']}) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationRequiresController() + + +class ValidationRequiresTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_requires(self): + # Test `requires` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + + result, ___ = self.request('All', 'POST', '/validation', doc=False, + params={'requiresParamForAll': 'param'}) + self.assertIn('requiresParamForAll', result) + + result, ___ = self.request( + 'All', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'requiresParamForAll': 'param', + } + ) + self.assertIn('customParam', result) + self.assertIn('requiresParamForAll', result) + + self.request('All', 'POST', '/validation', doc=False, expected_status=400) + + self.request('All', 'POST', '/validation', doc=False, params={'customParam': 'param'}, + expected_status=400) + + self.request('All', 'POST', '/validation', doc=False, params={'requiresParamForClient': 'param'}, + expected_status=400) + + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + result, ___ = self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'requiresParamForAll': 'param', + 'requiresParamForClient': 'param', + } + ) + self.assertIn('requiresParamForAll', result) + self.assertIn('requiresParamForClient', result) + + result, ___ = self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'requiresParamForAll': 'param', + 'requiresParamForClient': 'param', + } + ) + self.assertIn('customParam', result) + self.assertIn('requiresParamForAll', result) + self.assertIn('requiresParamForClient', result) + + self.request('Client', 'POST', '/validation', doc=False, expected_status=400) + + self.request('Client', 'POST', '/validation', doc=False, params={'customParam': 'param'}, + expected_status=400) + + self.request('Client', 'POST', '/validation', doc=False, params={'requiresParamForAll': 'param'}, + expected_status=400) + + self.request('Client', 'POST', '/validation', doc=False, params={ + 'requiresParamForClient': + 'param', + }, expected_status=400) + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + result, ___ = self.request('Admin', 'POST', '/validation', doc=False, params={ + 'requiresParamForAll': 'param', + 'requiresParamForAdmin': 'param', + }) + self.assertIn('requiresParamForAll', result) + self.assertIn('requiresParamForAdmin', result) + result, ___ = self.request( + 'Admin', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + 'requiresParamForAll': 'param', + 'requiresParamForAdmin': 'param', + } + ) + self.assertIn('customParam', result) + self.assertIn('requiresParamForAll', result) + self.assertIn('requiresParamForAdmin', result) + + self.request('Admin', 'POST', '/validation', doc=False, expected_status=400) + + self.request('Admin', 'POST', '/validation', doc=False, params={'customParam': 'param'}, + expected_status=400) + + self.request( + 'Admin', 'POST', '/validation', doc=False, + params={ + 'requiresParamForAll': 'param', + 'requiresParamForClient': 'param', + }, + expected_status=400 + ) + + self.request('Admin', 'POST', '/validation', doc=False, params={'requiresParamForAdmin': 'param'}, + expected_status=400) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/tests/test_validation_types.py b/restfulpy/tests/test_validation_types.py new file mode 100644 index 0000000..4aa0866 --- /dev/null +++ b/restfulpy/tests/test_validation_types.py @@ -0,0 +1,137 @@ +import copy +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationTypesController(RestController): + + @json + @validate_form( + types={ + 'typedParam1': float, + 'typedParam2': float, + 'typedParam3': float, + }, + client={ + 'types': { + 'typedParam1': int, + 'typedParam2': int + } + }, + admin={ + 'types': { + 'typedParam1': complex, + 'typedParam4': complex + } + } + ) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationTypesController() + + +class ValidationTypesTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_types(self): + # Test `type` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + result, ___ = self.request( + 'All', 'POST', '/validation', + doc=False, + params={ + 'typedParam1': '1', + 'typedParam2': '2', + 'typedParam3': '3', + 'typedParam4': '4' + } + ) + self.assertEqual(type(result['typedParam1']), float) + self.assertEqual(type(result['typedParam2']), float) + self.assertEqual(type(result['typedParam3']), float) + self.assertEqual(type(result['typedParam4']), str) + + self.request( + 'All', 'POST', '/validation', + doc=False, + params={'typedParam1': 'not_convertible'}, + expected_status=400 + ) + + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + result, ___ = self.request( + 'Client', 'POST', '/validation', + doc=False, + params={ + 'typedParam1': '1', + 'typedParam2': '2', + 'typedParam3': '3', + 'typedParam4': '4' + } + ) + self.assertEqual(type(result['typedParam1']), int) + self.assertEqual(type(result['typedParam2']), int) + self.assertEqual(type(result['typedParam3']), float) + self.assertEqual(type(result['typedParam4']), str) + + self.request( + 'Client', 'POST', '/validation', + doc=False, + params={'typedParam1': 'not_convertible'}, + expected_status=400 + ) + + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + result, ___ = self.request( + 'Admin', 'POST', '/validation', + doc=False, + params={ + 'typedParam1': '1', + 'typedParam2': '2', + 'typedParam3': '3', + 'typedParam4': '4' + } + ) + # type complex is dict + self.assertEqual(type(result['typedParam1']), dict) + self.assertEqual(type(result['typedParam2']), float) + self.assertEqual(type(result['typedParam3']), float) + self.assertEqual(type(result['typedParam4']), dict) + + self.request( + 'Admin', 'POST', '/validation', + doc=False, + params={'typedParam1': 'not_convertible'}, + expected_status=400 + ) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/tests/test_validation_whiltelist.py b/restfulpy/tests/test_validation_whiltelist.py new file mode 100644 index 0000000..7b26bd9 --- /dev/null +++ b/restfulpy/tests/test_validation_whiltelist.py @@ -0,0 +1,160 @@ +import copy +import unittest + +from nanohttp import context, json, settings + +from restfulpy.principal import DummyIdentity +from restfulpy.testing import WebAppTestCase +from restfulpy.tests.helpers import MockupApplication +from restfulpy.validation import validate_form +from restfulpy.controllers import RestController, RootController + + +class ValidationWhitelistController(RestController): + + @json + @validate_form(whitelist=['whitelistParamForAll'], + client={'whitelist': ['whitelistParamForClient']}, + admin={'whitelist': ['whitelistParamForAdmin']}) + def post(self): + result = copy.deepcopy(context.form) + result.update(context.query_string) + return result + + +class Root(RootController): + validation = ValidationWhitelistController() + + +class ValidationWhitelistTestCase(WebAppTestCase): + application = MockupApplication('MockupApplication', Root()) + + @classmethod + def configure_app(cls): + super().configure_app() + settings.merge(""" + logging: + loggers: + default: + level: info + """) + + def test_validation_whitelist(self): + # Test `whitelist` + # role -> All + self.wsgi_app.jwt_token = DummyIdentity().dump().decode() + result, ___ = self.request('All', 'POST', '/validation', doc=False, + params={'whitelistParamForAll': 'param'}) + self.assertIn('whitelistParamForAll', result) + self.request('All', 'POST', '/validation', doc=False) + self.request( + 'All', 'POST', '/validation', doc=False, + params={ + 'whitelistParamForAll': 'param', + 'customParam': 'param' + }, + expected_status=400 + ) + self.request('All', 'POST', '/validation', doc=False, params={'customParam': 'param'}, + expected_status=400) + self.request('All', 'POST', '/validation', doc=False, params={'whitelistParamForClient': 'param', }, + expected_status=400) + # ----------------------------- + # role -> Client + self.wsgi_app.jwt_token = DummyIdentity('client').dump().decode() + + result, ___ = self.request('Client', 'POST', '/validation', doc=False, + params={'whitelistParamForAll': 'param'}) + self.assertIn('whitelistParamForAll', result) + + result, ___ = self.request('Client', 'POST', '/validation', doc=False, + params={'whitelistParamForClient': 'param'}) + self.assertIn('whitelistParamForClient', result) + + result, ___ = self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'whitelistParamForAll': 'param', + 'whitelistParamForClient': 'param', + } + ) + self.assertIn('whitelistParamForAll', result) + self.assertIn('whitelistParamForClient', result) + + self.request('Client', 'POST', '/validation', doc=False) + + self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'whitelistParamForAll': 'param', + 'customParam': 'param', + }, + expected_status=400 + ) + + self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'customParam': 'param', + }, + expected_status=400 + ) + + self.request( + 'Client', 'POST', '/validation', doc=False, + params={ + 'whitelistParamForAdmin': 'param', + }, + expected_status=400 + ) + + # ----------------------------- + # role -> Admin + self.wsgi_app.jwt_token = DummyIdentity('admin').dump().decode() + + result, ___ = self.request('Admin', 'POST', '/validation', doc=False, + params={'whitelistParamForAll': 'param'}) + self.assertIn('whitelistParamForAll', result) + + result, ___ = self.request('Admin', 'POST', '/validation', doc=False, + params={'whitelistParamForAdmin': 'param'}) + self.assertIn('whitelistParamForAdmin', result) + + result, ___ = self.request( + 'Admin', 'POST', '/validation', doc=False, + params={ + 'whitelistParamForAll': 'param', + 'whitelistParamForAdmin': 'param', + } + ) + self.assertIn('whitelistParamForAll', result) + self.assertIn('whitelistParamForAdmin', result) + + self.request('Admin', 'POST', '/validation', doc=False) + + self.request( + 'Admin', 'POST', '/validation', doc=False, + params={ + 'whitelistParamForAll': 'param', + 'customParam': 'param', + }, + expected_status=400 + ) + + self.request('Admin', 'POST', '/validation', doc=False, params={ + 'customParam': 'param', + }, expected_status=400) + + self.request( + 'Admin', 'POST', '/validation', doc=False, + params={ + 'whitelistParamForAll': 'param', + 'whitelistParamForAdmin': 'param', + 'whitelistParamForClient': 'param', + }, + expected_status=400 + ) + + +if __name__ == '__main__': # pragma: no cover + unittest.main() diff --git a/restfulpy/validation.py b/restfulpy/validation.py index f51960a..b09f9d9 100644 --- a/restfulpy/validation.py +++ b/restfulpy/validation.py @@ -1,4 +1,5 @@ import functools +import re from itertools import chain from nanohttp import context @@ -15,6 +16,7 @@ def __init__( requires=None, exact=None, types=None, + pattern=None, **rules_per_role ): self.default_rules = {} @@ -39,6 +41,9 @@ def __init__( if types: self.default_rules['types'] = types + if pattern: + self.default_rules['pattern'] = pattern + self._rules_per_role = rules_per_role def extract_rulesets(self, rule_name, user_rules): @@ -107,11 +112,23 @@ def __call__(self, *args, **kwargs): except ValueError: raise HttpBadRequest('The field: %s must be %s' % (field, desired_type)) + pattern_pairs = self.extract_rules_pair('pattern', user_rules) + if pattern_pairs: + pattern_keys = set(pattern_pairs.keys()) + for collection in input_collections: + for field in set(collection) & pattern_keys: + desired_pattern = pattern_pairs[field] + pattern = re.compile(desired_pattern) if isinstance(desired_pattern, str) else desired_pattern + if pattern.match(collection[field]) is None: + raise HttpBadRequest( + 'The field %s: %s must be matched with %s pattern' % + (field, collection[field], pattern.pattern) + ) return args, kwargs def validate_form(blacklist=None, exclude=None, filter_=None, whitelist=None, requires=None, exact=None, types=None, - **rules_per_role): + pattern=None, **rules_per_role): """Creates a validation decorator based on given rules: :param blacklist: A list fields to raise :class:`nanohttp.exceptions.HttpBadRequest` if exists in request. @@ -125,6 +142,8 @@ def validate_form(blacklist=None, exclude=None, filter_=None, whitelist=None, re exact match. :param types: A dictionary of fields and their expected types. Fields will be casted to expected types if possible. Otherwise :class:`nanohttp.exceptions.HttpBadRequest` will be raised. + :param pattern: A dictionary of fields and their expected regex patterns. Fields will be matched by expected pattern + if possible. Otherwise :class:`nanohttp.exceptions.HttpBadRequest` will be raised. :param rules_per_role: A dictionary ``{ role: { ... } }``, which you can apply above rules to single role. @@ -133,7 +152,7 @@ def validate_form(blacklist=None, exclude=None, filter_=None, whitelist=None, re def decorator(func): validator = FormValidator(blacklist=blacklist, exclude=exclude, filter_=filter_, whitelist=whitelist, - requires=requires, exact=exact, types=types, **rules_per_role) + requires=requires, exact=exact, types=types, pattern=pattern, **rules_per_role) @functools.wraps(func) def wrapper(*args, **kwargs):