import logging import config from helper import resolve_product_usable_id etcd_client = config.etcd_client class ValidationException(Exception): """Validation Error""" class Field: def __init__(self, _name, _type, _value=None, validators=None): if validators is None: validators = [] assert isinstance(validators, list) self.name = _name self.value = _value self.type = _type self.validators = validators def is_valid(self): if not isinstance(self.value, self.type): try: self.value = self.type(self.value) except Exception: raise ValidationException("Incorrect Type for '{}' field".format(self.name)) for validator in self.validators: validator() def __repr__(self): return self.name class BaseSchema: def __init__(self): self.fields = [getattr(self, field) for field in dir(self) if isinstance(getattr(self, field), Field)] def validation(self): # custom validation is optional return True def is_valid(self): for field in self.fields: field.is_valid() for parent in self.__class__.__bases__: parent.validation(self) self.validation() for field in self.fields: setattr(self, field.name, field.value) def return_data(self): return { field.name: field.value for field in self.fields } def get(dictionary: dict, key: str, return_default=False, default=None): if dictionary is None: raise ValidationException('No data provided at all.') try: value = dictionary[key] except KeyError: if return_default: return default raise ValidationException("Missing data for '{}' field.".format(key)) else: return value class AddProductSchema(BaseSchema): def __init__(self, data): self.email = Field('email', str, get(data, 'email')) self.password = Field('password', str, get(data, 'password')) self.specs = Field('specs', dict, get(data, 'specs')) super().__init__() class UserRegisterPaymentSchema(BaseSchema): def __init__(self, data): self.email = Field('email', str, get(data, 'email')) self.password = Field('password', str, get(data, 'password')) self.card_number = Field('card_number', str, get(data, 'card_number')) self.cvc = Field('cvc', str, get(data, 'cvc')) self.expiry_year = Field('expiry_year', int, get(data, 'expiry_year')) self.expiry_month = Field('expiry_month', int, get(data, 'expiry_month')) self.card_holder_name = Field('card_holder_name', str, get(data, 'card_holder_name')) super().__init__() class ProductOrderSchema(BaseSchema): def __init__(self, data): self.email = Field('email', str, get(data, 'email')) self.password = Field('password', str, get(data, 'password')) self.product_id = Field('product_id', str, get(data, 'product_id'), validators=[self.product_id_validation]) super().__init__() def product_id_validation(self): product_uuid = resolve_product_usable_id(self.product_id.value, etcd_client) if product_uuid: self.product_id.value = product_uuid else: raise ValidationException('Invalid Product ID') class OrderListSchema(BaseSchema): def __init__(self, data): self.email = Field('email', str, get(data, 'email')) self.password = Field('password', str, get(data, 'password')) super().__init__() def make_return_message(err, status_code=200): logging.debug('message: {}'.format(str(err))) return {'message': str(err)}, status_code def create_schema(specification, data): fields = {} for feature_name, feature_detail in specification['features'].items(): if not feature_detail['constant']: fields[feature_name] = Field(feature_name, eval(feature_detail['unit']['type']), get(data, feature_name)) return type('{}Schema'.format(specification['name']), (BaseSchema,), fields)