Remove v2 schema and validation tests
With the removal of the v2.0 APIs in Queens, the schema for specific v2.0 actions can be removed. Change-Id: Id63dbdab0b13995e6d42d19f6c224f23a2ce8d19
This commit is contained in:
parent
489e4b1420
commit
665cca0161
@ -47,24 +47,6 @@ region_update = {
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
# Schema for Service v2
|
||||
|
||||
_service_properties_v2 = {
|
||||
'enabled': parameter_types.boolean,
|
||||
'description': {
|
||||
'type': ['string', 'null']
|
||||
},
|
||||
'name': parameter_types.name,
|
||||
'type': _service_properties_type
|
||||
}
|
||||
|
||||
service_create_v2 = {
|
||||
'type': 'object',
|
||||
'properties': _service_properties_v2,
|
||||
'required': ['type'],
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
# Schema for Service v3
|
||||
|
||||
_service_properties = {
|
||||
|
@ -23,44 +23,6 @@ _identity_name = {
|
||||
'pattern': '[\S]+'
|
||||
}
|
||||
|
||||
# Schema for Identity v2 API
|
||||
|
||||
_user_properties_v2 = {
|
||||
'description': validation.nullable(parameter_types.description),
|
||||
'enabled': parameter_types.boolean,
|
||||
'tenantId': validation.nullable(parameter_types.id_string),
|
||||
'name': _identity_name,
|
||||
'username': _identity_name,
|
||||
'password': {
|
||||
'type': ['string', 'null']
|
||||
}
|
||||
}
|
||||
|
||||
user_create_v2 = {
|
||||
'type': 'object',
|
||||
'properties': _user_properties_v2,
|
||||
'anyOf': [
|
||||
{
|
||||
'required': ['username']
|
||||
},
|
||||
{
|
||||
'required': ['name']
|
||||
}
|
||||
],
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
# NOTE(ghugo): minProperties value should really be 1, however it
|
||||
# is currently set to 0 to avoid breaking backwards compatibility,
|
||||
# and tempest tests.
|
||||
|
||||
user_update_v2 = {
|
||||
'type': 'object',
|
||||
'properties': _user_properties_v2,
|
||||
'minProperties': 0,
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
# Schema for Identity v3 API
|
||||
|
||||
_user_properties = {
|
||||
@ -116,10 +78,3 @@ group_update = {
|
||||
'minProperties': 1,
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
enable_user_v2 = {
|
||||
'type': 'object',
|
||||
'properties': {'enabled': parameter_types.boolean},
|
||||
'required': ['enabled'],
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
@ -97,34 +97,3 @@ domain_update = {
|
||||
'minProperties': 1,
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
_tenant_properties = {
|
||||
'description': validation.nullable(parameter_types.description),
|
||||
'enabled': parameter_types.boolean,
|
||||
'name': _name_properties,
|
||||
'id': validation.nullable(parameter_types.id_string)
|
||||
}
|
||||
|
||||
tenant_create = {
|
||||
'type': 'object',
|
||||
'properties': _tenant_properties,
|
||||
'required': ['name'],
|
||||
'not': {
|
||||
'required': ['is_domain']
|
||||
},
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
tenant_update = {
|
||||
'type': 'object',
|
||||
'properties': _tenant_properties,
|
||||
'not': {
|
||||
'anyOf': [
|
||||
{'required': ['is_domain']},
|
||||
{'required': ['domain_id']}
|
||||
]
|
||||
},
|
||||
'tenantId': validation.nullable(parameter_types.id_string),
|
||||
'minProperties': 1,
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
@ -1,161 +0,0 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import copy
|
||||
|
||||
from keystone.common import validation
|
||||
from keystone.common.validation import parameter_types
|
||||
from keystone.common.validation import validators
|
||||
|
||||
|
||||
_project_properties = {
|
||||
'id': parameter_types.id_string,
|
||||
'name': parameter_types.name,
|
||||
'enabled': parameter_types.boolean,
|
||||
'description': validation.nullable(parameter_types.description),
|
||||
}
|
||||
|
||||
_token_properties = {
|
||||
'audit_ids': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'string',
|
||||
},
|
||||
'minItems': 1,
|
||||
'maxItems': 2,
|
||||
},
|
||||
'id': {'type': 'string'},
|
||||
'expires': {'type': 'string'},
|
||||
'issued_at': {'type': 'string'},
|
||||
'tenant': {
|
||||
'type': 'object',
|
||||
'properties': _project_properties,
|
||||
'required': ['id', 'name', 'enabled'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
}
|
||||
|
||||
_role_properties = {
|
||||
'name': parameter_types.name,
|
||||
}
|
||||
|
||||
_user_properties = {
|
||||
'id': parameter_types.id_string,
|
||||
'name': parameter_types.name,
|
||||
'username': parameter_types.name,
|
||||
'roles': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': _role_properties,
|
||||
'required': ['name'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'roles_links': {
|
||||
'type': 'array',
|
||||
'maxItems': 0,
|
||||
},
|
||||
}
|
||||
|
||||
_metadata_properties = {
|
||||
'is_admin': {'type': 'integer'},
|
||||
'roles': {
|
||||
'type': 'array',
|
||||
'items': {'type': 'string'},
|
||||
},
|
||||
}
|
||||
|
||||
_endpoint_properties = {
|
||||
'id': {'type': 'string'},
|
||||
'adminURL': parameter_types.url,
|
||||
'internalURL': parameter_types.url,
|
||||
'publicURL': parameter_types.url,
|
||||
'region': {'type': 'string'},
|
||||
}
|
||||
|
||||
_service_properties = {
|
||||
'type': {'type': 'string'},
|
||||
'name': parameter_types.name,
|
||||
'endpoints_links': {
|
||||
'type': 'array',
|
||||
'maxItems': 0,
|
||||
},
|
||||
'endpoints': {
|
||||
'type': 'array',
|
||||
'minItems': 1,
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': _endpoint_properties,
|
||||
'required': ['id', 'publicURL'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_base_access_properties = {
|
||||
'metadata': {
|
||||
'type': 'object',
|
||||
'properties': _metadata_properties,
|
||||
'required': ['is_admin', 'roles'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'serviceCatalog': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': _service_properties,
|
||||
'required': ['name', 'type', 'endpoints_links', 'endpoints'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'token': {
|
||||
'type': 'object',
|
||||
'properties': _token_properties,
|
||||
'required': ['audit_ids', 'id', 'expires', 'issued_at'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'user': {
|
||||
'type': 'object',
|
||||
'properties': _user_properties,
|
||||
'required': ['id', 'name', 'username', 'roles', 'roles_links'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
}
|
||||
|
||||
_unscoped_access_properties = copy.deepcopy(_base_access_properties)
|
||||
unscoped_metadata = _unscoped_access_properties['metadata']
|
||||
unscoped_metadata['properties']['roles']['maxItems'] = 0
|
||||
_unscoped_access_properties['user']['properties']['roles']['maxItems'] = 0
|
||||
_unscoped_access_properties['serviceCatalog']['maxItems'] = 0
|
||||
|
||||
_scoped_access_properties = copy.deepcopy(_base_access_properties)
|
||||
_scoped_access_properties['metadata']['properties']['roles']['minItems'] = 1
|
||||
_scoped_access_properties['serviceCatalog']['minItems'] = 1
|
||||
_scoped_access_properties['user']['properties']['roles']['minItems'] = 1
|
||||
|
||||
base_token_schema = {
|
||||
'type': 'object',
|
||||
'required': ['metadata', 'user', 'serviceCatalog', 'token'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
unscoped_token_schema = copy.deepcopy(base_token_schema)
|
||||
unscoped_token_schema['properties'] = _unscoped_access_properties
|
||||
|
||||
scoped_token_schema = copy.deepcopy(base_token_schema)
|
||||
scoped_token_schema['properties'] = _scoped_access_properties
|
||||
|
||||
# Validator objects
|
||||
unscoped_validator = validators.SchemaValidator(unscoped_token_schema)
|
||||
scoped_validator = validators.SchemaValidator(scoped_token_schema)
|
@ -1,366 +0,0 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import uuid
|
||||
|
||||
from keystone.catalog import schema as catalog_schema
|
||||
from keystone.common.validation import validators
|
||||
from keystone import exception
|
||||
from keystone.identity import schema as identity_schema
|
||||
from keystone.resource import schema as resource_schema
|
||||
from keystone.tests import unit
|
||||
|
||||
|
||||
_INVALID_NAMES = [True, 24, ' ', '']
|
||||
|
||||
_VALID_ENABLED_FORMATS = [True, False]
|
||||
|
||||
_INVALID_ENABLED_FORMATS = ['some string', 1, 0, 'True', 'False']
|
||||
|
||||
|
||||
class TenantValidationTestCase(unit.BaseTestCase):
|
||||
"""Test for v2 Tenant API Validation."""
|
||||
|
||||
def setUp(self):
|
||||
super(TenantValidationTestCase, self).setUp()
|
||||
schema_tenant_create = resource_schema.tenant_create
|
||||
schema_tenant_update = resource_schema.tenant_update
|
||||
self.create_validator = validators.SchemaValidator(
|
||||
schema_tenant_create)
|
||||
self.update_validator = validators.SchemaValidator(
|
||||
schema_tenant_update)
|
||||
|
||||
def test_validate_tenant_create_success(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_tenant_create_success_with_empty_description(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'description': ''
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_tenant_create_success_with_extra_parameters(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'description': 'Test tenant',
|
||||
'enabled': True,
|
||||
'extra': 'test'
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_tenant_create_failure_with_missing_name(self):
|
||||
request = {
|
||||
'description': 'Test tenant',
|
||||
'enabled': True
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_create_fails_with_invalid_name(self):
|
||||
"""Exception when validating a create request with invalid `name`."""
|
||||
for invalid_name in _INVALID_NAMES:
|
||||
request = {'name': invalid_name}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_create_failure_with_empty_request(self):
|
||||
request = {}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_create_failure_with_is_domain(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'description': 'Test tenant',
|
||||
'enabled': True,
|
||||
'is_domain': False
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_create_with_enabled(self):
|
||||
"""Validate `enabled` as boolean-like values."""
|
||||
for valid_enabled in _VALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': valid_enabled
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_tenant_create_with_invalid_enabled_fails(self):
|
||||
"""Exception is raised when `enabled` isn't a boolean-like value."""
|
||||
for invalid_enabled in _INVALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': invalid_enabled
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_update_success(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'description': 'Test tenant',
|
||||
'enabled': True
|
||||
}
|
||||
self.update_validator.validate(request)
|
||||
|
||||
def test_validate_tenant_update_success_with_optional_ids(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'description': 'Test tenant',
|
||||
'enabled': True,
|
||||
'tenantId': uuid.uuid4().hex,
|
||||
'id': uuid.uuid4().hex
|
||||
}
|
||||
self.update_validator.validate(request)
|
||||
|
||||
def test_validate_tenant_update_with_domain_id(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'domain_id': uuid.uuid4().hex
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_update_with_is_domain(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'is_domain': False
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_update_with_empty_request(self):
|
||||
request = {}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_update_fails_with_invalid_name(self):
|
||||
"""Exception when validating an update request with invalid `name`."""
|
||||
for invalid_name in _INVALID_NAMES:
|
||||
request = {'name': invalid_name}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_tenant_update_with_enabled(self):
|
||||
"""Validate `enabled` as boolean-like values."""
|
||||
for valid_enabled in _VALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': valid_enabled
|
||||
}
|
||||
self.update_validator.validate(request)
|
||||
|
||||
def test_validate_tenant_update_with_invalid_enabled_fails(self):
|
||||
"""Exception is raised when `enabled` isn't a boolean-like value."""
|
||||
for invalid_enabled in _INVALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': invalid_enabled
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_validator.validate,
|
||||
request)
|
||||
|
||||
|
||||
class ServiceValidationTestCase(unit.BaseTestCase):
|
||||
"""Test for V2 Service API Validation."""
|
||||
|
||||
def setUp(self):
|
||||
super(ServiceValidationTestCase, self).setUp()
|
||||
|
||||
schema_create = catalog_schema.service_create
|
||||
self.create_validator = validators.SchemaValidator(schema_create)
|
||||
|
||||
def test_validate_service_create_succeeds(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'type': uuid.uuid4().hex,
|
||||
'description': uuid.uuid4().hex
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_service_create_fails_with_invalid_params(self):
|
||||
request = {
|
||||
'bogus': uuid.uuid4().hex
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_service_create_fails_with_invalid_name(self):
|
||||
for invalid_name in _INVALID_NAMES:
|
||||
request = {
|
||||
'type': uuid.uuid4().hex,
|
||||
'name': invalid_name
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_service_create_with_enabled(self):
|
||||
"""Validate `enabled` as boolean-like values."""
|
||||
for valid_enabled in _VALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'type': uuid.uuid4().hex,
|
||||
'enabled': valid_enabled
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_service_create_with_invalid_enabled_fails(self):
|
||||
"""Exception is raised when `enabled` isn't a boolean-like value."""
|
||||
for invalid_enabled in _INVALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'type': uuid.uuid4().hex,
|
||||
'enabled': invalid_enabled
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_service_create_with_invalid_type(self):
|
||||
request = {
|
||||
'type': -42
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_service_create_with_type_too_large(self):
|
||||
request = {
|
||||
'type': 'a' * 256
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
|
||||
class UserValidationTestCase(unit.BaseTestCase):
|
||||
"""Test for V2 User API Validation."""
|
||||
|
||||
def setUp(self):
|
||||
super(UserValidationTestCase, self).setUp()
|
||||
|
||||
schema_user_create = identity_schema.user_create_v2
|
||||
schema_user_update = identity_schema.user_update_v2
|
||||
self.create_validator = validators.SchemaValidator(schema_user_create)
|
||||
self.update_validator = validators.SchemaValidator(schema_user_update)
|
||||
|
||||
def test_validate_user_create_succeeds_with_name(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_user_create_succeeds_with_username(self):
|
||||
request = {
|
||||
'username': uuid.uuid4().hex
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_user_create_fails_with_invalid_params(self):
|
||||
request = {
|
||||
'bogus': uuid.uuid4().hex
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_user_create_fails_with_invalid_name(self):
|
||||
for invalid_name in _INVALID_NAMES:
|
||||
request = {
|
||||
'name': invalid_name
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_user_create_with_enabled(self):
|
||||
"""Validate `enabled` as boolean-like values."""
|
||||
for valid_enabled in _VALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': valid_enabled
|
||||
}
|
||||
self.create_validator.validate(request)
|
||||
|
||||
def test_validate_user_create_with_invalid_enabled_fails(self):
|
||||
"""Exception is raised when `enabled` isn't a boolean-like value."""
|
||||
for invalid_enabled in _INVALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': invalid_enabled
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.create_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_user_update_succeeds_with_name(self):
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': True
|
||||
}
|
||||
self.update_validator.validate(request)
|
||||
|
||||
def test_validate_user_update_succeeds_with_username(self):
|
||||
request = {
|
||||
'username': uuid.uuid4().hex,
|
||||
'enabled': True
|
||||
}
|
||||
self.update_validator.validate(request)
|
||||
|
||||
def test_validate_user_update_succeeds_with_no_params(self):
|
||||
request = {}
|
||||
self.update_validator.validate(request)
|
||||
|
||||
def test_validate_user_update_fails_with_invalid_name(self):
|
||||
for invalid_name in _INVALID_NAMES:
|
||||
request = {
|
||||
'name': invalid_name
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_validator.validate,
|
||||
request)
|
||||
|
||||
def test_validate_user_update_with_enabled(self):
|
||||
"""Validate `enabled` as boolean-like values."""
|
||||
for valid_enabled in _VALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': valid_enabled
|
||||
}
|
||||
self.update_validator.validate(request)
|
||||
|
||||
def test_validate_user_update_with_invalid_enabled_fails(self):
|
||||
"""Exception is raised when `enabled` isn't a boolean-like value."""
|
||||
for invalid_enabled in _INVALID_ENABLED_FORMATS:
|
||||
request = {
|
||||
'name': uuid.uuid4().hex,
|
||||
'enabled': invalid_enabled
|
||||
}
|
||||
self.assertRaises(exception.SchemaValidationError,
|
||||
self.update_validator.validate,
|
||||
request)
|
Loading…
Reference in New Issue
Block a user