Code

Ticket #3011: #3011-extendable_auth_user.diff

File #3011-extendable_auth_user.diff, 40.0 KB (added by Kronuz, 2 years ago)
Line 
1diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
2index b03bce4..be60e96 100644
3--- django/contrib/admin/sites.py
4+++ django/contrib/admin/sites.py
5@@ -1,7 +1,6 @@
6 import re
7 from django import http, template
8 from django.contrib.admin import ModelAdmin, actions
9-from django.contrib.admin.forms import AdminAuthenticationForm
10 from django.contrib.auth import REDIRECT_FIELD_NAME
11 from django.contrib.contenttypes import views as contenttype_views
12 from django.views.decorators.csrf import csrf_protect
13@@ -315,6 +314,7 @@ class AdminSite(object):
14         Displays the login form for the given HttpRequest.
15         """
16         from django.contrib.auth.views import login
17+        from django.contrib.admin.forms import AdminAuthenticationForm
18         context = {
19             'title': _('Log in'),
20             'root_path': self.root_path,
21diff --git a/django/contrib/auth/base.py b/django/contrib/auth/base.py
22new file mode 100644
23index 0000000..30131e0
24--- /dev/null
25+++ django/contrib/auth/base.py
26@@ -0,0 +1,469 @@
27+import datetime
28+import urllib
29+
30+from django.contrib import auth
31+from django.contrib.auth.signals import user_logged_in
32+from django.core.exceptions import ImproperlyConfigured
33+from django.db import models
34+from django.db.models.manager import EmptyManager
35+from django.contrib.contenttypes.models import ContentType
36+from django.utils.encoding import smart_str
37+from django.utils.hashcompat import md5_constructor, sha_constructor
38+from django.utils.translation import ugettext_lazy as _
39+from django.utils.crypto import constant_time_compare
40+
41+
42+UNUSABLE_PASSWORD = '!' # This will never be a valid hash
43+
44+def get_hexdigest(algorithm, salt, raw_password):
45+    """
46+    Returns a string of the hexdigest of the given plaintext password and salt
47+    using the given algorithm ('md5', 'sha1' or 'crypt').
48+    """
49+    raw_password, salt = smart_str(raw_password), smart_str(salt)
50+    if algorithm == 'crypt':
51+        try:
52+            import crypt
53+        except ImportError:
54+            raise ValueError('"crypt" password algorithm not supported in this environment')
55+        return crypt.crypt(raw_password, salt)
56+
57+    if algorithm == 'md5':
58+        return md5_constructor(salt + raw_password).hexdigest()
59+    elif algorithm == 'sha1':
60+        return sha_constructor(salt + raw_password).hexdigest()
61+    raise ValueError("Got unknown password algorithm type in password.")
62+
63+def check_password(raw_password, enc_password):
64+    """
65+    Returns a boolean of whether the raw_password was correct. Handles
66+    encryption formats behind the scenes.
67+    """
68+    algo, salt, hsh = enc_password.split('$')
69+    return constant_time_compare(hsh, get_hexdigest(algo, salt, raw_password))
70+
71+def update_last_login(sender, user, **kwargs):
72+    """
73+    A signal receiver which updates the last_login date for
74+    the user logging in.
75+    """
76+    user.last_login = datetime.datetime.now()
77+    user.save()
78+user_logged_in.connect(update_last_login)
79+
80+class SiteProfileNotAvailable(Exception):
81+    pass
82+
83+class PermissionManager(models.Manager):
84+    def get_by_natural_key(self, codename, app_label, model):
85+        return self.get(
86+            codename=codename,
87+            content_type=ContentType.objects.get_by_natural_key(app_label, model)
88+        )
89+
90+class Permission(models.Model):
91+    """The permissions system provides a way to assign permissions to specific users and groups of users.
92+
93+    The permission system is used by the Django admin site, but may also be useful in your own code. The Django admin site uses permissions as follows:
94+
95+        - The "add" permission limits the user's ability to view the "add" form and add an object.
96+        - The "change" permission limits a user's ability to view the change list, view the "change" form and change an object.
97+        - The "delete" permission limits the ability to delete an object.
98+
99+    Permissions are set globally per type of object, not per specific object instance. It is possible to say "Mary may change news stories," but it's not currently possible to say "Mary may change news stories, but only the ones she created herself" or "Mary may only change news stories that have a certain status or publication date."
100+
101+    Three basic permissions -- add, change and delete -- are automatically created for each Django model.
102+    """
103+    name = models.CharField(_('name'), max_length=50)
104+    content_type = models.ForeignKey(ContentType)
105+    codename = models.CharField(_('codename'), max_length=100)
106+    objects = PermissionManager()
107+
108+    class Meta:
109+        verbose_name = _('permission')
110+        verbose_name_plural = _('permissions')
111+        unique_together = (('content_type', 'codename'),)
112+        ordering = ('content_type__app_label', 'content_type__model', 'codename')
113+
114+    def __unicode__(self):
115+        return u"%s | %s | %s" % (
116+            unicode(self.content_type.app_label),
117+            unicode(self.content_type),
118+            unicode(self.name))
119+
120+    def natural_key(self):
121+        return (self.codename,) + self.content_type.natural_key()
122+    natural_key.dependencies = ['contenttypes.contenttype']
123+
124+class Group(models.Model):
125+    """Groups are a generic way of categorizing users to apply permissions, or some other label, to those users. A user can belong to any number of groups.
126+
127+    A user in a group automatically has all the permissions granted to that group. For example, if the group Site editors has the permission can_edit_home_page, any user in that group will have that permission.
128+
129+    Beyond permissions, groups are a convenient way to categorize users to apply some label, or extended functionality, to them. For example, you could create a group 'Special users', and you could write code that would do special things to those users -- such as giving them access to a members-only portion of your site, or sending them members-only e-mail messages.
130+    """
131+    name = models.CharField(_('name'), max_length=80, unique=True)
132+    permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
133+
134+    class Meta:
135+        verbose_name = _('group')
136+        verbose_name_plural = _('groups')
137+
138+    def __unicode__(self):
139+        return self.name
140+
141+class UserManager(models.Manager):
142+    def create_user(self, username, email, password=None):
143+        """
144+        Creates and saves a User with the given username, e-mail and password.
145+        """
146+        now = datetime.datetime.now()
147+
148+        # Normalize the address by lowercasing the domain part of the email
149+        # address.
150+        try:
151+            email_name, domain_part = email.strip().split('@', 1)
152+        except ValueError:
153+            pass
154+        else:
155+            email = '@'.join([email_name, domain_part.lower()])
156+
157+        user = self.model(username=username, email=email, is_staff=False,
158+                         is_active=True, is_superuser=False, last_login=now,
159+                         date_joined=now)
160+
161+        user.set_password(password)
162+        user.save(using=self._db)
163+        return user
164+
165+    def create_superuser(self, username, email, password):
166+        u = self.create_user(username, email, password)
167+        u.is_staff = True
168+        u.is_active = True
169+        u.is_superuser = True
170+        u.save(using=self._db)
171+        return u
172+
173+    def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
174+        "Generates a random password with the given length and given allowed_chars"
175+        # Note that default value of allowed_chars does not have "I" or letters
176+        # that look like it -- just to avoid confusion.
177+        from random import choice
178+        return ''.join([choice(allowed_chars) for i in range(length)])
179+
180+
181+# A few helper functions for common logic between User and AnonymousUser.
182+def _user_get_all_permissions(user, obj):
183+    permissions = set()
184+    anon = user.is_anonymous()
185+    for backend in auth.get_backends():
186+        if not anon or backend.supports_anonymous_user:
187+            if hasattr(backend, "get_all_permissions"):
188+                if obj is not None:
189+                    if backend.supports_object_permissions:
190+                        permissions.update(
191+                            backend.get_all_permissions(user, obj)
192+                        )
193+                else:
194+                    permissions.update(backend.get_all_permissions(user))
195+    return permissions
196+
197+
198+def _user_has_perm(user, perm, obj):
199+    anon = user.is_anonymous()
200+    active = user.is_active
201+    for backend in auth.get_backends():
202+        if (not active and not anon and backend.supports_inactive_user) or \
203+                    (not anon or backend.supports_anonymous_user):
204+            if hasattr(backend, "has_perm"):
205+                if obj is not None:
206+                    if (backend.supports_object_permissions and
207+                        backend.has_perm(user, perm, obj)):
208+                            return True
209+                else:
210+                    if backend.has_perm(user, perm):
211+                        return True
212+    return False
213+
214+
215+def _user_has_module_perms(user, app_label):
216+    anon = user.is_anonymous()
217+    active = user.is_active
218+    for backend in auth.get_backends():
219+        if (not active and not anon and backend.supports_inactive_user) or \
220+                    (not anon or backend.supports_anonymous_user):
221+            if hasattr(backend, "has_module_perms"):
222+                if backend.has_module_perms(user, app_label):
223+                    return True
224+    return False
225+
226+
227+class UserTemplate(models.Model):
228+    """
229+    Users within the Django authentication system are represented by this model.
230+
231+    Username and password are required. Other fields are optional.
232+    """
233+    username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
234+    first_name = models.CharField(_('first name'), max_length=60, blank=True)
235+    last_name = models.CharField(_('last name'), max_length=60, blank=True)
236+    email = models.EmailField(_('e-mail address'), max_length=255, blank=True)
237+    password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
238+    is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
239+    is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
240+    is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
241+    last_login = models.DateTimeField(_('last login'), default=datetime.datetime.now)
242+    date_joined = models.DateTimeField(_('date joined'), default=datetime.datetime.now)
243+    groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
244+        help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
245+    user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True)
246+    objects = UserManager()
247+
248+    class Meta:
249+        abstract = True
250+
251+    def __unicode__(self):
252+        return self.username
253+
254+    def get_absolute_url(self):
255+        return "/users/%s/" % urllib.quote(smart_str(self.username))
256+
257+    def is_anonymous(self):
258+        """
259+        Always returns False. This is a way of comparing User objects to
260+        anonymous users.
261+        """
262+        return False
263+
264+    def is_authenticated(self):
265+        """
266+        Always return True. This is a way to tell if the user has been
267+        authenticated in templates.
268+        """
269+        return True
270+
271+    def get_full_name(self):
272+        "Returns the first_name plus the last_name, with a space in between."
273+        full_name = u'%s %s' % (self.first_name, self.last_name)
274+        return full_name.strip()
275+
276+    def set_password(self, raw_password):
277+        if raw_password is None:
278+            self.set_unusable_password()
279+        else:
280+            import random
281+            algo = 'sha1'
282+            salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
283+            hsh = get_hexdigest(algo, salt, raw_password)
284+            self.password = '%s$%s$%s' % (algo, salt, hsh)
285+
286+    def check_password(self, raw_password):
287+        """
288+        Returns a boolean of whether the raw_password was correct. Handles
289+        encryption formats behind the scenes.
290+        """
291+        # Backwards-compatibility check. Older passwords won't include the
292+        # algorithm or salt.
293+        if '$' not in self.password:
294+            is_correct = (self.password == get_hexdigest('md5', '', raw_password))
295+            if is_correct:
296+                # Convert the password to the new, more secure format.
297+                self.set_password(raw_password)
298+                self.save()
299+            return is_correct
300+        return check_password(raw_password, self.password)
301+
302+    def set_unusable_password(self):
303+        # Sets a value that will never be a valid hash
304+        self.password = UNUSABLE_PASSWORD
305+
306+    def has_usable_password(self):
307+        if self.password is None \
308+            or self.password == UNUSABLE_PASSWORD:
309+            return False
310+        else:
311+            return True
312+
313+    def get_group_permissions(self, obj=None):
314+        """
315+        Returns a list of permission strings that this user has through
316+        his/her groups. This method queries all available auth backends.
317+        If an object is passed in, only permissions matching this object
318+        are returned.
319+        """
320+        permissions = set()
321+        for backend in auth.get_backends():
322+            if hasattr(backend, "get_group_permissions"):
323+                if obj is not None:
324+                    if backend.supports_object_permissions:
325+                        permissions.update(
326+                            backend.get_group_permissions(self, obj)
327+                        )
328+                else:
329+                    permissions.update(backend.get_group_permissions(self))
330+        return permissions
331+
332+    def get_all_permissions(self, obj=None):
333+        return _user_get_all_permissions(self, obj)
334+
335+    def has_perm(self, perm, obj=None):
336+        """
337+        Returns True if the user has the specified permission. This method
338+        queries all available auth backends, but returns immediately if any
339+        backend returns True. Thus, a user who has permission from a single
340+        auth backend is assumed to have permission in general. If an object
341+        is provided, permissions for this specific object are checked.
342+        """
343+
344+        # Active superusers have all permissions.
345+        if self.is_active and self.is_superuser:
346+            return True
347+
348+        # Otherwise we need to check the backends.
349+        return _user_has_perm(self, perm, obj)
350+
351+    def has_perms(self, perm_list, obj=None):
352+        """
353+        Returns True if the user has each of the specified permissions.
354+        If object is passed, it checks if the user has all required perms
355+        for this object.
356+        """
357+        for perm in perm_list:
358+            if not self.has_perm(perm, obj):
359+                return False
360+        return True
361+
362+    def has_module_perms(self, app_label):
363+        """
364+        Returns True if the user has any permissions in the given app
365+        label. Uses pretty much the same logic as has_perm, above.
366+        """
367+        # Active superusers have all permissions.
368+        if self.is_active and self.is_superuser:
369+            return True
370+
371+        return _user_has_module_perms(self, app_label)
372+
373+    def get_and_delete_messages(self):
374+        messages = []
375+        for m in self.message_set.all():
376+            messages.append(m.message)
377+            m.delete()
378+        return messages
379+
380+    def email_user(self, subject, message, from_email=None):
381+        "Sends an e-mail to this User."
382+        from django.core.mail import send_mail
383+        send_mail(subject, message, from_email, [self.email])
384+
385+    def get_profile(self):
386+        """
387+        Returns site-specific profile for this user. Raises
388+        SiteProfileNotAvailable if this site does not allow profiles.
389+        """
390+        if not hasattr(self, '_profile_cache'):
391+            from django.conf import settings
392+            if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
393+                raise SiteProfileNotAvailable('You need to set AUTH_PROFILE_MO'
394+                                              'DULE in your project settings')
395+            try:
396+                app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
397+            except ValueError:
398+                raise SiteProfileNotAvailable('app_label and model_name should'
399+                        ' be separated by a dot in the AUTH_PROFILE_MODULE set'
400+                        'ting')
401+
402+            try:
403+                model = models.get_model(app_label, model_name)
404+                if model is None:
405+                    raise SiteProfileNotAvailable('Unable to load the profile '
406+                        'model, check AUTH_PROFILE_MODULE in your project sett'
407+                        'ings')
408+                self._profile_cache = model._default_manager.using(self._state.db).get(user__id__exact=self.id)
409+                self._profile_cache.user = self
410+            except (ImportError, ImproperlyConfigured):
411+                raise SiteProfileNotAvailable
412+        return self._profile_cache
413+
414+    def _get_message_set(self):
415+        import warnings
416+        warnings.warn('The user messaging API is deprecated. Please update'
417+                      ' your code to use the new messages framework.',
418+                      category=DeprecationWarning)
419+        return self._message_set
420+    message_set = property(_get_message_set)
421+
422+
423+class AnonymousUser(object):
424+    id = None
425+    username = ''
426+    is_staff = False
427+    is_active = False
428+    is_superuser = False
429+    _groups = EmptyManager()
430+    _user_permissions = EmptyManager()
431+
432+    def __init__(self):
433+        pass
434+
435+    def __unicode__(self):
436+        return 'AnonymousUser'
437+
438+    def __str__(self):
439+        return unicode(self).encode('utf-8')
440+
441+    def __eq__(self, other):
442+        return isinstance(other, self.__class__)
443+
444+    def __ne__(self, other):
445+        return not self.__eq__(other)
446+
447+    def __hash__(self):
448+        return 1 # instances always return the same hash value
449+
450+    def save(self):
451+        raise NotImplementedError
452+
453+    def delete(self):
454+        raise NotImplementedError
455+
456+    def set_password(self, raw_password):
457+        raise NotImplementedError
458+
459+    def check_password(self, raw_password):
460+        raise NotImplementedError
461+
462+    def _get_groups(self):
463+        return self._groups
464+    groups = property(_get_groups)
465+
466+    def _get_user_permissions(self):
467+        return self._user_permissions
468+    user_permissions = property(_get_user_permissions)
469+
470+    def get_group_permissions(self, obj=None):
471+        return set()
472+
473+    def get_all_permissions(self, obj=None):
474+        return _user_get_all_permissions(self, obj=obj)
475+
476+    def has_perm(self, perm, obj=None):
477+        return _user_has_perm(self, perm, obj=obj)
478+
479+    def has_perms(self, perm_list, obj=None):
480+        for perm in perm_list:
481+            if not self.has_perm(perm, obj):
482+                return False
483+        return True
484+
485+    def has_module_perms(self, module):
486+        return _user_has_module_perms(self, module)
487+
488+    def get_and_delete_messages(self):
489+        return []
490+
491+    def is_anonymous(self):
492+        return True
493+
494+    def is_authenticated(self):
495+        return False
496\ No newline at end of file
497diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
498index 24195c8..b96ed76 100644
499--- django/contrib/auth/models.py
500+++ django/contrib/auth/models.py
501@@ -1,398 +1,36 @@
502-import datetime
503-import urllib
504-
505-from django.contrib import auth
506-from django.contrib.auth.signals import user_logged_in
507-from django.core.exceptions import ImproperlyConfigured
508+from django.conf import settings
509 from django.db import models
510-from django.db.models.manager import EmptyManager
511-from django.contrib.contenttypes.models import ContentType
512-from django.utils.encoding import smart_str
513-from django.utils.hashcompat import md5_constructor, sha_constructor
514 from django.utils.translation import ugettext_lazy as _
515-from django.utils.crypto import constant_time_compare
516-
517-
518-UNUSABLE_PASSWORD = '!' # This will never be a valid hash
519-
520-def get_hexdigest(algorithm, salt, raw_password):
521-    """
522-    Returns a string of the hexdigest of the given plaintext password and salt
523-    using the given algorithm ('md5', 'sha1' or 'crypt').
524-    """
525-    raw_password, salt = smart_str(raw_password), smart_str(salt)
526-    if algorithm == 'crypt':
527-        try:
528-            import crypt
529-        except ImportError:
530-            raise ValueError('"crypt" password algorithm not supported in this environment')
531-        return crypt.crypt(raw_password, salt)
532-
533-    if algorithm == 'md5':
534-        return md5_constructor(salt + raw_password).hexdigest()
535-    elif algorithm == 'sha1':
536-        return sha_constructor(salt + raw_password).hexdigest()
537-    raise ValueError("Got unknown password algorithm type in password.")
538-
539-def check_password(raw_password, enc_password):
540-    """
541-    Returns a boolean of whether the raw_password was correct. Handles
542-    encryption formats behind the scenes.
543-    """
544-    algo, salt, hsh = enc_password.split('$')
545-    return constant_time_compare(hsh, get_hexdigest(algo, salt, raw_password))
546-
547-def update_last_login(sender, user, **kwargs):
548-    """
549-    A signal receiver which updates the last_login date for
550-    the user logging in.
551-    """
552-    user.last_login = datetime.datetime.now()
553-    user.save()
554-user_logged_in.connect(update_last_login)
555-
556-class SiteProfileNotAvailable(Exception):
557-    pass
558-
559-class PermissionManager(models.Manager):
560-    def get_by_natural_key(self, codename, app_label, model):
561-        return self.get(
562-            codename=codename,
563-            content_type=ContentType.objects.get_by_natural_key(app_label, model)
564-        )
565-
566-class Permission(models.Model):
567-    """The permissions system provides a way to assign permissions to specific users and groups of users.
568-
569-    The permission system is used by the Django admin site, but may also be useful in your own code. The Django admin site uses permissions as follows:
570-
571-        - The "add" permission limits the user's ability to view the "add" form and add an object.
572-        - The "change" permission limits a user's ability to view the change list, view the "change" form and change an object.
573-        - The "delete" permission limits the ability to delete an object.
574-
575-    Permissions are set globally per type of object, not per specific object instance. It is possible to say "Mary may change news stories," but it's not currently possible to say "Mary may change news stories, but only the ones she created herself" or "Mary may only change news stories that have a certain status or publication date."
576-
577-    Three basic permissions -- add, change and delete -- are automatically created for each Django model.
578-    """
579-    name = models.CharField(_('name'), max_length=50)
580-    content_type = models.ForeignKey(ContentType)
581-    codename = models.CharField(_('codename'), max_length=100)
582-    objects = PermissionManager()
583-
584-    class Meta:
585-        verbose_name = _('permission')
586-        verbose_name_plural = _('permissions')
587-        unique_together = (('content_type', 'codename'),)
588-        ordering = ('content_type__app_label', 'content_type__model', 'codename')
589-
590-    def __unicode__(self):
591-        return u"%s | %s | %s" % (
592-            unicode(self.content_type.app_label),
593-            unicode(self.content_type),
594-            unicode(self.name))
595 
596-    def natural_key(self):
597-        return (self.codename,) + self.content_type.natural_key()
598-    natural_key.dependencies = ['contenttypes.contenttype']
599+from django.contrib.auth.base import *
600+
601+if hasattr(settings, 'AUTH_USER_MODULE'):
602+    # Grab the AUTH_USER_MODULE path and classname from the settings.
603+    # auth_user_module_parts[0] = module path
604+    # auth_user_module_parts[1] = class name
605+    auth_user_module_parts = settings.AUTH_USER_MODULE.rsplit('.', 1)
606+    auth_user_module = __import__(auth_user_module_parts[0], {}, {}, [auth_user_module_parts[0]])
607+    # Store the auth_user model so it is accessible with the standard
608+    # 'from django.contrib.auth.models import User'
609+    User = getattr(auth_user_module, auth_user_module_parts[1])
610+
611+    # Add te User model to the django models cache
612+    # These two lines allow the custom auth_user model to play nicely with syncdb
613+    # and other systems that rely on functions like
614+    # django.db.models.loading.get_model(...)
615+    from django.db.models.loading import cache
616+    cache.register_models('auth', User)
617+
618+    # We need to remove whatever we used as the AUTH_USER_MODUlE from the
619+    # db cache so apps like contenttypes don't think that it's part
620+    # of contrib.auth
621+    del cache.app_models['auth'][User.__name__.lower()]
622+else:
623+    class User(UserTemplate):
624+        class Meta:
625+            verbose_name = _('user')
626+            verbose_name_plural = _('users')
627 
628-class Group(models.Model):
629-    """Groups are a generic way of categorizing users to apply permissions, or some other label, to those users. A user can belong to any number of groups.
630-
631-    A user in a group automatically has all the permissions granted to that group. For example, if the group Site editors has the permission can_edit_home_page, any user in that group will have that permission.
632-
633-    Beyond permissions, groups are a convenient way to categorize users to apply some label, or extended functionality, to them. For example, you could create a group 'Special users', and you could write code that would do special things to those users -- such as giving them access to a members-only portion of your site, or sending them members-only e-mail messages.
634-    """
635-    name = models.CharField(_('name'), max_length=80, unique=True)
636-    permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
637-
638-    class Meta:
639-        verbose_name = _('group')
640-        verbose_name_plural = _('groups')
641-
642-    def __unicode__(self):
643-        return self.name
644-
645-class UserManager(models.Manager):
646-    def create_user(self, username, email, password=None):
647-        """
648-        Creates and saves a User with the given username, e-mail and password.
649-        """
650-        now = datetime.datetime.now()
651-
652-        # Normalize the address by lowercasing the domain part of the email
653-        # address.
654-        try:
655-            email_name, domain_part = email.strip().split('@', 1)
656-        except ValueError:
657-            pass
658-        else:
659-            email = '@'.join([email_name, domain_part.lower()])
660-
661-        user = self.model(username=username, email=email, is_staff=False,
662-                         is_active=True, is_superuser=False, last_login=now,
663-                         date_joined=now)
664-
665-        user.set_password(password)
666-        user.save(using=self._db)
667-        return user
668-
669-    def create_superuser(self, username, email, password):
670-        u = self.create_user(username, email, password)
671-        u.is_staff = True
672-        u.is_active = True
673-        u.is_superuser = True
674-        u.save(using=self._db)
675-        return u
676-
677-    def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
678-        "Generates a random password with the given length and given allowed_chars"
679-        # Note that default value of allowed_chars does not have "I" or letters
680-        # that look like it -- just to avoid confusion.
681-        from random import choice
682-        return ''.join([choice(allowed_chars) for i in range(length)])
683-
684-
685-# A few helper functions for common logic between User and AnonymousUser.
686-def _user_get_all_permissions(user, obj):
687-    permissions = set()
688-    anon = user.is_anonymous()
689-    for backend in auth.get_backends():
690-        if not anon or backend.supports_anonymous_user:
691-            if hasattr(backend, "get_all_permissions"):
692-                if obj is not None:
693-                    if backend.supports_object_permissions:
694-                        permissions.update(
695-                            backend.get_all_permissions(user, obj)
696-                        )
697-                else:
698-                    permissions.update(backend.get_all_permissions(user))
699-    return permissions
700-
701-
702-def _user_has_perm(user, perm, obj):
703-    anon = user.is_anonymous()
704-    active = user.is_active
705-    for backend in auth.get_backends():
706-        if (not active and not anon and backend.supports_inactive_user) or \
707-                    (not anon or backend.supports_anonymous_user):
708-            if hasattr(backend, "has_perm"):
709-                if obj is not None:
710-                    if (backend.supports_object_permissions and
711-                        backend.has_perm(user, perm, obj)):
712-                            return True
713-                else:
714-                    if backend.has_perm(user, perm):
715-                        return True
716-    return False
717-
718-
719-def _user_has_module_perms(user, app_label):
720-    anon = user.is_anonymous()
721-    active = user.is_active
722-    for backend in auth.get_backends():
723-        if (not active and not anon and backend.supports_inactive_user) or \
724-                    (not anon or backend.supports_anonymous_user):
725-            if hasattr(backend, "has_module_perms"):
726-                if backend.has_module_perms(user, app_label):
727-                    return True
728-    return False
729-
730-
731-class User(models.Model):
732-    """
733-    Users within the Django authentication system are represented by this model.
734-
735-    Username and password are required. Other fields are optional.
736-    """
737-    username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
738-    first_name = models.CharField(_('first name'), max_length=60, blank=True)
739-    last_name = models.CharField(_('last name'), max_length=60, blank=True)
740-    email = models.EmailField(_('e-mail address'), max_length=255, blank=True)
741-    password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
742-    is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
743-    is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
744-    is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
745-    last_login = models.DateTimeField(_('last login'), default=datetime.datetime.now)
746-    date_joined = models.DateTimeField(_('date joined'), default=datetime.datetime.now)
747-    groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
748-        help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
749-    user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True)
750-    objects = UserManager()
751-
752-    class Meta:
753-        verbose_name = _('user')
754-        verbose_name_plural = _('users')
755-
756-    def __unicode__(self):
757-        return self.username
758-
759-    def get_absolute_url(self):
760-        return "/users/%s/" % urllib.quote(smart_str(self.username))
761-
762-    def is_anonymous(self):
763-        """
764-        Always returns False. This is a way of comparing User objects to
765-        anonymous users.
766-        """
767-        return False
768-
769-    def is_authenticated(self):
770-        """
771-        Always return True. This is a way to tell if the user has been
772-        authenticated in templates.
773-        """
774-        return True
775-
776-    def get_full_name(self):
777-        "Returns the first_name plus the last_name, with a space in between."
778-        full_name = u'%s %s' % (self.first_name, self.last_name)
779-        return full_name.strip()
780-
781-    def set_password(self, raw_password):
782-        if raw_password is None:
783-            self.set_unusable_password()
784-        else:
785-            import random
786-            algo = 'sha1'
787-            salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
788-            hsh = get_hexdigest(algo, salt, raw_password)
789-            self.password = '%s$%s$%s' % (algo, salt, hsh)
790-
791-    def check_password(self, raw_password):
792-        """
793-        Returns a boolean of whether the raw_password was correct. Handles
794-        encryption formats behind the scenes.
795-        """
796-        # Backwards-compatibility check. Older passwords won't include the
797-        # algorithm or salt.
798-        if '$' not in self.password:
799-            is_correct = (self.password == get_hexdigest('md5', '', raw_password))
800-            if is_correct:
801-                # Convert the password to the new, more secure format.
802-                self.set_password(raw_password)
803-                self.save()
804-            return is_correct
805-        return check_password(raw_password, self.password)
806-
807-    def set_unusable_password(self):
808-        # Sets a value that will never be a valid hash
809-        self.password = UNUSABLE_PASSWORD
810-
811-    def has_usable_password(self):
812-        if self.password is None \
813-            or self.password == UNUSABLE_PASSWORD:
814-            return False
815-        else:
816-            return True
817-
818-    def get_group_permissions(self, obj=None):
819-        """
820-        Returns a list of permission strings that this user has through
821-        his/her groups. This method queries all available auth backends.
822-        If an object is passed in, only permissions matching this object
823-        are returned.
824-        """
825-        permissions = set()
826-        for backend in auth.get_backends():
827-            if hasattr(backend, "get_group_permissions"):
828-                if obj is not None:
829-                    if backend.supports_object_permissions:
830-                        permissions.update(
831-                            backend.get_group_permissions(self, obj)
832-                        )
833-                else:
834-                    permissions.update(backend.get_group_permissions(self))
835-        return permissions
836-
837-    def get_all_permissions(self, obj=None):
838-        return _user_get_all_permissions(self, obj)
839-
840-    def has_perm(self, perm, obj=None):
841-        """
842-        Returns True if the user has the specified permission. This method
843-        queries all available auth backends, but returns immediately if any
844-        backend returns True. Thus, a user who has permission from a single
845-        auth backend is assumed to have permission in general. If an object
846-        is provided, permissions for this specific object are checked.
847-        """
848-
849-        # Active superusers have all permissions.
850-        if self.is_active and self.is_superuser:
851-            return True
852-
853-        # Otherwise we need to check the backends.
854-        return _user_has_perm(self, perm, obj)
855-
856-    def has_perms(self, perm_list, obj=None):
857-        """
858-        Returns True if the user has each of the specified permissions.
859-        If object is passed, it checks if the user has all required perms
860-        for this object.
861-        """
862-        for perm in perm_list:
863-            if not self.has_perm(perm, obj):
864-                return False
865-        return True
866-
867-    def has_module_perms(self, app_label):
868-        """
869-        Returns True if the user has any permissions in the given app
870-        label. Uses pretty much the same logic as has_perm, above.
871-        """
872-        # Active superusers have all permissions.
873-        if self.is_active and self.is_superuser:
874-            return True
875-
876-        return _user_has_module_perms(self, app_label)
877-
878-    def get_and_delete_messages(self):
879-        messages = []
880-        for m in self.message_set.all():
881-            messages.append(m.message)
882-            m.delete()
883-        return messages
884-
885-    def email_user(self, subject, message, from_email=None):
886-        "Sends an e-mail to this User."
887-        from django.core.mail import send_mail
888-        send_mail(subject, message, from_email, [self.email])
889-
890-    def get_profile(self):
891-        """
892-        Returns site-specific profile for this user. Raises
893-        SiteProfileNotAvailable if this site does not allow profiles.
894-        """
895-        if not hasattr(self, '_profile_cache'):
896-            from django.conf import settings
897-            if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
898-                raise SiteProfileNotAvailable('You need to set AUTH_PROFILE_MO'
899-                                              'DULE in your project settings')
900-            try:
901-                app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
902-            except ValueError:
903-                raise SiteProfileNotAvailable('app_label and model_name should'
904-                        ' be separated by a dot in the AUTH_PROFILE_MODULE set'
905-                        'ting')
906-
907-            try:
908-                model = models.get_model(app_label, model_name)
909-                if model is None:
910-                    raise SiteProfileNotAvailable('Unable to load the profile '
911-                        'model, check AUTH_PROFILE_MODULE in your project sett'
912-                        'ings')
913-                self._profile_cache = model._default_manager.using(self._state.db).get(user__id__exact=self.id)
914-                self._profile_cache.user = self
915-            except (ImportError, ImproperlyConfigured):
916-                raise SiteProfileNotAvailable
917-        return self._profile_cache
918-
919-    def _get_message_set(self):
920-        import warnings
921-        warnings.warn('The user messaging API is deprecated. Please update'
922-                      ' your code to use the new messages framework.',
923-                      category=DeprecationWarning)
924-        return self._message_set
925-    message_set = property(_get_message_set)
926 
927 class Message(models.Model):
928     """
929@@ -408,77 +46,3 @@ class Message(models.Model):
930 
931     def __unicode__(self):
932         return self.message
933-
934-class AnonymousUser(object):
935-    id = None
936-    username = ''
937-    is_staff = False
938-    is_active = False
939-    is_superuser = False
940-    _groups = EmptyManager()
941-    _user_permissions = EmptyManager()
942-
943-    def __init__(self):
944-        pass
945-
946-    def __unicode__(self):
947-        return 'AnonymousUser'
948-
949-    def __str__(self):
950-        return unicode(self).encode('utf-8')
951-
952-    def __eq__(self, other):
953-        return isinstance(other, self.__class__)
954-
955-    def __ne__(self, other):
956-        return not self.__eq__(other)
957-
958-    def __hash__(self):
959-        return 1 # instances always return the same hash value
960-
961-    def save(self):
962-        raise NotImplementedError
963-
964-    def delete(self):
965-        raise NotImplementedError
966-
967-    def set_password(self, raw_password):
968-        raise NotImplementedError
969-
970-    def check_password(self, raw_password):
971-        raise NotImplementedError
972-
973-    def _get_groups(self):
974-        return self._groups
975-    groups = property(_get_groups)
976-
977-    def _get_user_permissions(self):
978-        return self._user_permissions
979-    user_permissions = property(_get_user_permissions)
980-
981-    def get_group_permissions(self, obj=None):
982-        return set()
983-
984-    def get_all_permissions(self, obj=None):
985-        return _user_get_all_permissions(self, obj=obj)
986-
987-    def has_perm(self, perm, obj=None):
988-        return _user_has_perm(self, perm, obj=obj)
989-
990-    def has_perms(self, perm_list, obj=None):
991-        for perm in perm_list:
992-            if not self.has_perm(perm, obj):
993-                return False
994-        return True
995-
996-    def has_module_perms(self, module):
997-        return _user_has_module_perms(self, module)
998-
999-    def get_and_delete_messages(self):
1000-        return []
1001-
1002-    def is_anonymous(self):
1003-        return True
1004-
1005-    def is_authenticated(self):
1006-        return False