"""Base Field Definition.""" from typing import Self from payee.connectors.secure_data.exceptions import ( SecureDocumentFieldValidationException, ) class Field: """Definition of a secure field.""" _value_type: type = None def __init__(self, name, **kwargs): """Set properties on field definition.""" self._name = name self._encrypt = kwargs.get('encrypt', True) self._obscure_in_response = kwargs.get('obscure_in_response', False) self._required = kwargs.get('required', False) self._allowed_values = kwargs.get('allowed_values', None) self._value = None value = kwargs.get('value', None) if value: self.value = value @property def _obscured_value(self): return '***************' @property def _params(self): """Get field params.""" return { 'encrypt': self._encrypt, 'obscure_in_response': self._obscure_in_response, 'required': self._required, 'allowed_values': self._allowed_values, 'value': self._value, } def clone(self) -> Self: """Clone object.""" return type(self)(self._name, **self._params) @property def encrypt(self): """Encrypt property.""" return self._encrypt @property def has_obscured_value(self): """Check if the value is obscured (got value from FE for example).""" return self._obscure_in_response and self._value == self._obscured_value @staticmethod def is_empty(original_value): """Check if value is empty. For example for bool False is not an empty value, while for str '' is. """ return original_value is None @property def has_value(self): """Check if value is not None.""" return not self.is_empty(self._value) @property def name(self): """Get field name.""" return self._name @property def original_value(self): """Return the un-obscured value.""" return self._value def validate(self): """Validate state.""" if self._required and not self.has_value: raise SecureDocumentFieldValidationException(f'{self._name}: required') if ( self._allowed_values and self._value and self._value not in self._allowed_values ): raise SecureDocumentFieldValidationException( f'{self._name}: must be one of allowed values.' ) @property def value(self): """Get formatted value.""" if not self._obscure_in_response: return self._value if self._value: return self._obscured_value return None @value.setter def value(self, value): """Set value.""" if value is not None: # For boolean making bool(value) call lead to different issues # for example for obscured value self._value = self._value_type(value) if self._value_type else value self.validate()