initiating django package from a work in progress lib
This commit is contained in:
107
django_courriel/validation.py
Normal file
107
django_courriel/validation.py
Normal file
@ -0,0 +1,107 @@
|
||||
from email import errors as email_errors
|
||||
from email import headerregistry as email_reg
|
||||
from email import utils as email_utils
|
||||
|
||||
from django.core import exceptions, validators
|
||||
|
||||
|
||||
class CourrielError(Exception):
|
||||
""" Something went wrong and you'll have to take a guess """
|
||||
|
||||
|
||||
class InvalidAddressError(exceptions.ValidationError, CourrielError):
|
||||
""" Failed to parse an address definition """
|
||||
|
||||
|
||||
class InvalidRecipientsError(CourrielError):
|
||||
""" Can't be send to recipients """
|
||||
|
||||
|
||||
class InvalidSenderError(CourrielError):
|
||||
""" Missing or invalid sender """
|
||||
|
||||
|
||||
class InvalidGabarit(CourrielError):
|
||||
""" Something is wrong with the template """
|
||||
|
||||
|
||||
class InvalidFrontMatter(InvalidGabarit):
|
||||
""" Failed to parse template front matter """
|
||||
|
||||
|
||||
class MarkdownEmailError(InvalidGabarit):
|
||||
""" Error in markdown email or template loading """
|
||||
|
||||
|
||||
class UnresolvedVariableError(CourrielError):
|
||||
""" A template variable could not be resolved """
|
||||
|
||||
|
||||
class ValidAddress(email_reg.Address):
|
||||
""" extends email.headerregistry.Address so it can be used where django expect an email address.
|
||||
Except it should never be invalid """
|
||||
|
||||
def __new__(cls, display_name='', username='', domain='', addr_spec=None):
|
||||
""" Builds a ValidAddress from either an Address or a string, or raise InvalidAddressError """
|
||||
try:
|
||||
spec = addr_spec or f"{username}@{domain}"
|
||||
cls._validate_spec(spec)
|
||||
instance = super().__new__(cls)
|
||||
return instance
|
||||
except email_errors.InvalidHeaderDefect as e:
|
||||
raise InvalidAddressError(f"{spec}") from e
|
||||
|
||||
@classmethod
|
||||
def _validate_spec(cls, spec):
|
||||
try:
|
||||
validators.validate_email(spec)
|
||||
except exceptions.ValidationError as e:
|
||||
raise InvalidAddressError(f"{spec}") from e
|
||||
|
||||
@classmethod
|
||||
def factory(cls, input) -> 'ValidAddress':
|
||||
""" ensure Address instance from str, None or Address """
|
||||
if isinstance(input, ValidAddress):
|
||||
return input
|
||||
if isinstance(input, email_reg.Address): # converting to subclass
|
||||
return ValidAddress(display_name=input.display_name, username=input.username, domain=input.domain)
|
||||
if input is None:
|
||||
return ValidAddress(display_name='')
|
||||
if isinstance(input, str):
|
||||
try:
|
||||
name, spec = email_utils.parseaddr(input)
|
||||
return cls(name, addr_spec=spec)
|
||||
except email_errors.InvalidHeaderDefect:
|
||||
# parsing failed and may have split username, let's keep full input as display name
|
||||
return cls(display_name=input)
|
||||
raise TypeError(f"Cannot create ValidAddress from {type(input).__name__}")
|
||||
|
||||
@property
|
||||
def email(self):
|
||||
""" shorthand for addr_spec"""
|
||||
return self.addr_spec
|
||||
|
||||
|
||||
class ValidAddressList(list):
|
||||
""" only accepts valid addresses """
|
||||
|
||||
def _validate(self, value):
|
||||
""" converts to ValidAddress, may raise InvalidAddress """
|
||||
return ValidAddress.factory(value)
|
||||
|
||||
def __init__(self, iterable=()):
|
||||
validated = [self._validate(i) for i in iterable]
|
||||
super().__init__(validated)
|
||||
|
||||
def append(self, item):
|
||||
super().append(self._validate(item))
|
||||
|
||||
def insert(self, index, item):
|
||||
super().insert(index, self._validate(item))
|
||||
|
||||
def extend(self, items):
|
||||
for item in items:
|
||||
super().append(self._validate(item))
|
||||
|
||||
def __setitem__(self, index, item):
|
||||
super().__setitem__(index, self._validate(item))
|
||||
Reference in New Issue
Block a user