PageRenderTime 68ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/allauth/utils.py

https://gitlab.com/superiorthreads/django-allauth
Python | 273 lines | 254 code | 10 blank | 9 comment | 16 complexity | fcaa10268de3d2b95953d6e9dbf22c45 MD5 | raw file
  1. import base64
  2. import re
  3. import unicodedata
  4. import json
  5. from django.core.exceptions import ImproperlyConfigured
  6. from django.core.validators import validate_email, ValidationError
  7. from django.core import urlresolvers
  8. from django.contrib.sites.models import Site
  9. from django.db.models import FieldDoesNotExist
  10. from django.db.models.fields import (DateTimeField, DateField,
  11. EmailField, TimeField,
  12. BinaryField)
  13. from django.utils import six, dateparse
  14. from django.utils.six.moves.urllib.parse import urlsplit
  15. from django.core.serializers.json import DjangoJSONEncoder
  16. try:
  17. from django.utils.encoding import force_text, force_bytes
  18. except ImportError:
  19. from django.utils.encoding import force_unicode as force_text
  20. from allauth.compat import importlib
  21. def _generate_unique_username_base(txts, regex=None):
  22. from .account.adapter import get_adapter
  23. adapter = get_adapter()
  24. username = None
  25. regex = regex or '[^\w\s@+.-]'
  26. for txt in txts:
  27. if not txt:
  28. continue
  29. username = unicodedata.normalize('NFKD', force_text(txt))
  30. username = username.encode('ascii', 'ignore').decode('ascii')
  31. username = force_text(re.sub(regex, '', username).lower())
  32. # Django allows for '@' in usernames in order to accomodate for
  33. # project wanting to use e-mail for username. In allauth we don't
  34. # use this, we already have a proper place for putting e-mail
  35. # addresses (EmailAddress), so let's not use the full e-mail
  36. # address and only take the part leading up to the '@'.
  37. username = username.split('@')[0]
  38. username = username.strip()
  39. username = re.sub('\s+', '_', username)
  40. # Finally, validating base username without database lookups etc.
  41. try:
  42. username = adapter.clean_username(username, shallow=True)
  43. break
  44. except ValidationError:
  45. pass
  46. return username or 'user'
  47. def get_username_max_length():
  48. from .account.app_settings import USER_MODEL_USERNAME_FIELD
  49. if USER_MODEL_USERNAME_FIELD is not None:
  50. User = get_user_model()
  51. max_length = User._meta.get_field(USER_MODEL_USERNAME_FIELD).max_length
  52. else:
  53. max_length = 0
  54. return max_length
  55. def generate_unique_username(txts, regex=None):
  56. from .account.adapter import get_adapter
  57. adapter = get_adapter()
  58. username = _generate_unique_username_base(txts, regex)
  59. max_length = get_username_max_length()
  60. i = 0
  61. while True:
  62. try:
  63. if i:
  64. pfx = str(i + 1)
  65. else:
  66. pfx = ''
  67. ret = username[0:max_length - len(pfx)] + pfx
  68. return adapter.clean_username(ret)
  69. except ValidationError:
  70. i += 1
  71. def valid_email_or_none(email):
  72. ret = None
  73. try:
  74. if email:
  75. validate_email(email)
  76. if len(email) <= EmailField().max_length:
  77. ret = email
  78. except ValidationError:
  79. pass
  80. return ret
  81. def email_address_exists(email, exclude_user=None):
  82. from .account import app_settings as account_settings
  83. from .account.models import EmailAddress
  84. emailaddresses = EmailAddress.objects
  85. if exclude_user:
  86. emailaddresses = emailaddresses.exclude(user=exclude_user)
  87. ret = emailaddresses.filter(email__iexact=email).exists()
  88. if not ret:
  89. email_field = account_settings.USER_MODEL_EMAIL_FIELD
  90. if email_field:
  91. users = get_user_model().objects
  92. if exclude_user:
  93. users = users.exclude(pk=exclude_user.pk)
  94. ret = users.filter(**{email_field+'__iexact': email}).exists()
  95. return ret
  96. def import_attribute(path):
  97. assert isinstance(path, six.string_types)
  98. pkg, attr = path.rsplit('.', 1)
  99. ret = getattr(importlib.import_module(pkg), attr)
  100. return ret
  101. def import_callable(path_or_callable):
  102. if not hasattr(path_or_callable, '__call__'):
  103. ret = import_attribute(path_or_callable)
  104. else:
  105. ret = path_or_callable
  106. return ret
  107. try:
  108. from django.contrib.auth import get_user_model
  109. except ImportError:
  110. # To keep compatibility with Django 1.4
  111. def get_user_model():
  112. from . import app_settings
  113. from django.db.models import get_model
  114. try:
  115. app_label, model_name = app_settings.USER_MODEL.split('.')
  116. except ValueError:
  117. raise ImproperlyConfigured("AUTH_USER_MODEL must be of the"
  118. " form 'app_label.model_name'")
  119. user_model = get_model(app_label, model_name)
  120. if user_model is None:
  121. raise ImproperlyConfigured("AUTH_USER_MODEL refers to model"
  122. " '%s' that has not been installed"
  123. % app_settings.USER_MODEL)
  124. return user_model
  125. def get_current_site(request=None):
  126. """Wrapper around ``Site.objects.get_current`` to handle ``Site`` lookups
  127. by request in Django >= 1.8.
  128. :param request: optional request object
  129. :type request: :class:`django.http.HttpRequest`
  130. """
  131. # >= django 1.8
  132. if request and hasattr(Site.objects, '_get_site_by_request'):
  133. site = Site.objects.get_current(request=request)
  134. else:
  135. site = Site.objects.get_current()
  136. return site
  137. def resolve_url(to):
  138. """
  139. Subset of django.shortcuts.resolve_url (that one is 1.5+)
  140. """
  141. try:
  142. return urlresolvers.reverse(to)
  143. except urlresolvers.NoReverseMatch:
  144. # If this doesn't "feel" like a URL, re-raise.
  145. if '/' not in to and '.' not in to:
  146. raise
  147. # Finally, fall back and assume it's a URL
  148. return to
  149. def serialize_instance(instance):
  150. """
  151. Since Django 1.6 items added to the session are no longer pickled,
  152. but JSON encoded by default. We are storing partially complete models
  153. in the session (user, account, token, ...). We cannot use standard
  154. Django serialization, as these are models are not "complete" yet.
  155. Serialization will start complaining about missing relations et al.
  156. """
  157. data = {}
  158. for k, v in instance.__dict__.items():
  159. if k.startswith('_') or callable(v):
  160. continue
  161. try:
  162. if isinstance(instance._meta.get_field(k), BinaryField):
  163. v = force_text(base64.b64encode(v))
  164. except FieldDoesNotExist:
  165. pass
  166. data[k] = v
  167. return json.loads(json.dumps(data, cls=DjangoJSONEncoder))
  168. def deserialize_instance(model, data):
  169. ret = model()
  170. for k, v in data.items():
  171. if v is not None:
  172. try:
  173. f = model._meta.get_field(k)
  174. if isinstance(f, DateTimeField):
  175. v = dateparse.parse_datetime(v)
  176. elif isinstance(f, TimeField):
  177. v = dateparse.parse_time(v)
  178. elif isinstance(f, DateField):
  179. v = dateparse.parse_date(v)
  180. elif isinstance(f, BinaryField):
  181. v = force_bytes(
  182. base64.b64decode(
  183. force_bytes(v)))
  184. except FieldDoesNotExist:
  185. pass
  186. setattr(ret, k, v)
  187. return ret
  188. def set_form_field_order(form, fields_order):
  189. if hasattr(form.fields, 'keyOrder'):
  190. form.fields.keyOrder = fields_order
  191. else:
  192. # Python 2.7+
  193. from collections import OrderedDict
  194. assert isinstance(form.fields, OrderedDict)
  195. form.fields = OrderedDict((f, form.fields[f])
  196. for f in fields_order)
  197. def build_absolute_uri(request, location, protocol=None):
  198. """request.build_absolute_uri() helper
  199. Like request.build_absolute_uri, but gracefully handling
  200. the case where request is None.
  201. """
  202. from .account import app_settings as account_settings
  203. if request is None:
  204. site = get_current_site()
  205. bits = urlsplit(location)
  206. if not (bits.scheme and bits.netloc):
  207. uri = '{proto}://{domain}{url}'.format(
  208. proto=account_settings.DEFAULT_HTTP_PROTOCOL,
  209. domain=site.domain,
  210. url=location)
  211. else:
  212. uri = location
  213. else:
  214. uri = request.build_absolute_uri(location)
  215. # NOTE: We only force a protocol if we are instructed to do so
  216. # (via the `protocol` parameter, or, if the default is set to
  217. # HTTPS. The latter keeps compatibility with the debatable use
  218. # case of running your site under both HTTP and HTTPS, where one
  219. # would want to make sure HTTPS links end up in password reset
  220. # mails even while they were initiated on an HTTP password reset
  221. # form.
  222. if not protocol and account_settings.DEFAULT_HTTP_PROTOCOL == 'https':
  223. protocol = account_settings.DEFAULT_HTTP_PROTOCOL
  224. # (end NOTE)
  225. if protocol:
  226. uri = protocol + ':' + uri.partition(':')[2]
  227. return uri
  228. def get_form_class(forms, form_id, default_form):
  229. form_class = forms.get(form_id, default_form)
  230. if isinstance(form_class, six.string_types):
  231. form_class = import_attribute(form_class)
  232. return form_class
  233. def get_request_param(request, param, default=None):
  234. return request.POST.get(param) or request.GET.get(param, default)