| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- # This module is based on django-phone-number-field
- # https://github.com/stefanfoulis/django-phonenumber-field
- #
- # Here is the relevant copyright and permissions notice.
- #
- # Copyright (c) 2011 Stefan Foulis and contributors.
- #
- # Permission is hereby granted, free of charge, to any person
- # obtaining a copy of this software and associated documentation
- # files (the "Software"), to deal in the Software without
- # restriction, including without limitation the rights to use,
- # copy, modify, merge, publish, distribute, sublicense, and/or sell
- # copies of the Software, and to permit persons to whom the
- # Software is furnished to do so, subject to the following
- # conditions:
- #
- # The above copyright notice and this permission notice shall be
- # included in all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- # OTHER DEALINGS IN THE SOFTWARE.
-
- import six
-
- from django.core import validators
- from django.conf import settings
- from django.core.exceptions import ValidationError
- from django.utils.translation import ugettext_lazy as _
- from django.utils.encoding import python_2_unicode_compatible
-
- import phonenumbers
-
-
- @python_2_unicode_compatible
- class PhoneNumber(phonenumbers.phonenumber.PhoneNumber):
- """
- A extended version of phonenumbers.phonenumber.PhoneNumber that provides
- some neat and more pythonic, easy to access methods. This makes using a
- PhoneNumber instance much easier, especially in templates and such.
- """
- format_map = {
- 'E164': phonenumbers.PhoneNumberFormat.E164,
- 'INTERNATIONAL': phonenumbers.PhoneNumberFormat.INTERNATIONAL,
- 'NATIONAL': phonenumbers.PhoneNumberFormat.NATIONAL,
- 'RFC3966': phonenumbers.PhoneNumberFormat.RFC3966,
- }
-
- @classmethod
- def from_string(cls, phone_number, region=None):
- phone_number_obj = cls()
- if region is None:
- region = getattr(settings, 'PHONENUMBER_DEFAULT_REGION', None)
- phonenumbers.parse(number=phone_number, region=region,
- keep_raw_input=True, numobj=phone_number_obj)
- return phone_number_obj
-
- def __str__(self):
- format_string = getattr(
- settings, 'PHONENUMBER_DEFAULT_FORMAT', 'INTERNATIONAL')
- fmt = self.format_map[format_string]
- if self.is_valid():
- return self.format_as(fmt)
- return self.raw_input
-
- def is_valid(self):
- """
- checks whether the number supplied is actually valid
- """
- return phonenumbers.is_valid_number(self)
-
- def format_as(self, format):
- if self.is_valid():
- return phonenumbers.format_number(self, format)
- else:
- return self.raw_input
-
- @property
- def as_international(self):
- return self.format_as(phonenumbers.PhoneNumberFormat.INTERNATIONAL)
-
- @property
- def as_e164(self):
- return self.format_as(phonenumbers.PhoneNumberFormat.E164)
-
- @property
- def as_national(self):
- return self.format_as(phonenumbers.PhoneNumberFormat.NATIONAL)
-
- @property
- def as_rfc3966(self):
- return self.format_as(phonenumbers.PhoneNumberFormat.RFC3966)
-
- def __len__(self):
- return len(six.text_type(self))
-
- def __eq__(self, other):
- if type(other) == PhoneNumber:
- return self.as_e164 == other.as_e164
- else:
- return super(PhoneNumber, self).__eq__(other)
-
-
- def to_python(value):
- if value in validators.EMPTY_VALUES: # None or ''
- phone_number = None
- elif value and isinstance(value, six.string_types):
- try:
- phone_number = PhoneNumber.from_string(phone_number=value)
- except phonenumbers.phonenumberutil.NumberParseException:
- # the string provided is not a valid PhoneNumber.
- phone_number = PhoneNumber(raw_input=value)
- elif isinstance(value, PhoneNumber):
- phone_number = value
- return phone_number
-
-
- class PhoneNumberDescriptor(object):
- """
- The descriptor for the phone number attribute on the model instance.
- Returns a PhoneNumber when accessed so you can do stuff like::
-
- >>> instance.phone_number.as_international
-
- Assigns a phone number object on assignment so you can do::
-
- >>> instance.phone_number = PhoneNumber(...)
- or
- >>> instance.phone_number = '+414204242'
-
- """
-
- def __init__(self, field):
- self.field = field
-
- def __get__(self, instance=None, owner=None):
- if instance is None:
- raise AttributeError(
- "The '%s' attribute can only be accessed from %s instances."
- % (self.field.name, owner.__name__))
- return instance.__dict__[self.field.name]
-
- def __set__(self, instance, value):
- instance.__dict__[self.field.name] = to_python(value)
-
-
- def validate_international_phonenumber(value):
- phone_number = to_python(value)
- if phone_number and not phone_number.is_valid():
- raise ValidationError(_(u'The phone number entered is not valid.'))
|