summaryrefslogtreecommitdiff
path: root/django/contrib/auth
diff options
context:
space:
mode:
authorAdrian Holovaty <adrian@holovaty.com>2006-05-02 01:31:56 +0000
committerAdrian Holovaty <adrian@holovaty.com>2006-05-02 01:31:56 +0000
commitf69cf70ed813a8cd7e1f963a14ae39103e8d5265 (patch)
treed3b32e84cd66573b3833ddf662af020f8ef2f7a8 /django/contrib/auth
parentd5dbeaa9be359a4c794885c2e9f1b5a7e5e51fb8 (diff)
MERGED MAGIC-REMOVAL BRANCH TO TRUNK. This change is highly backwards-incompatible. Please read http://code.djangoproject.com/wiki/RemovingTheMagic for upgrade instructions.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@2809 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/contrib/auth')
-rw-r--r--django/contrib/auth/__init__.py2
-rw-r--r--django/contrib/auth/create_superuser.py84
-rw-r--r--django/contrib/auth/decorators.py25
-rw-r--r--django/contrib/auth/forms.py108
-rw-r--r--django/contrib/auth/handlers/modpython.py12
-rw-r--r--django/contrib/auth/management.py53
-rw-r--r--django/contrib/auth/middleware.py19
-rw-r--r--django/contrib/auth/models.py264
-rw-r--r--django/contrib/auth/views.py84
9 files changed, 645 insertions, 6 deletions
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
index e69de29bb2..ac7b40aca6 100644
--- a/django/contrib/auth/__init__.py
+++ b/django/contrib/auth/__init__.py
@@ -0,0 +1,2 @@
+LOGIN_URL = '/accounts/login/'
+REDIRECT_FIELD_NAME = 'next'
diff --git a/django/contrib/auth/create_superuser.py b/django/contrib/auth/create_superuser.py
new file mode 100644
index 0000000000..ab5ca36f50
--- /dev/null
+++ b/django/contrib/auth/create_superuser.py
@@ -0,0 +1,84 @@
+"""
+Helper function for creating superusers in the authentication system.
+"""
+
+from django.core import validators
+from django.contrib.auth.models import User
+import getpass
+import os
+import sys
+
+def createsuperuser(username=None, email=None, password=None):
+ """
+ Helper function for creating a superuser from the command line. All
+ arguments are optional and will be prompted-for if invalid or not given.
+ """
+ try:
+ import pwd
+ except ImportError:
+ default_username = ''
+ else:
+ # Determine the current system user's username, to use as a default.
+ default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
+
+ # Determine whether the default username is taken, so we don't display
+ # it as an option.
+ if default_username:
+ try:
+ User.objects.get(username=default_username)
+ except User.DoesNotExist:
+ pass
+ else:
+ default_username = ''
+
+ try:
+ while 1:
+ if not username:
+ input_msg = 'Username'
+ if default_username:
+ input_msg += ' (Leave blank to use %r)' % default_username
+ username = raw_input(input_msg + ': ')
+ if default_username and username == '':
+ username = default_username
+ if not username.isalnum():
+ sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
+ username = None
+ try:
+ User.objects.get(username=username)
+ except User.DoesNotExist:
+ break
+ else:
+ sys.stderr.write("Error: That username is already taken.\n")
+ username = None
+ while 1:
+ if not email:
+ email = raw_input('E-mail address: ')
+ try:
+ validators.isValidEmail(email, None)
+ except validators.ValidationError:
+ sys.stderr.write("Error: That e-mail address is invalid.\n")
+ email = None
+ else:
+ break
+ while 1:
+ if not password:
+ password = getpass.getpass()
+ password2 = getpass.getpass('Password (again): ')
+ if password != password2:
+ sys.stderr.write("Error: Your passwords didn't match.\n")
+ password = None
+ continue
+ if password.strip() == '':
+ sys.stderr.write("Error: Blank passwords aren't allowed.\n")
+ password = None
+ continue
+ break
+ except KeyboardInterrupt:
+ sys.stderr.write("\nOperation cancelled.\n")
+ sys.exit(1)
+ u = User.objects.create_user(username, email, password)
+ u.is_staff = True
+ u.is_active = True
+ u.is_superuser = True
+ u.save()
+ print "Superuser created successfully."
diff --git a/django/contrib/auth/decorators.py b/django/contrib/auth/decorators.py
new file mode 100644
index 0000000000..4b264cf815
--- /dev/null
+++ b/django/contrib/auth/decorators.py
@@ -0,0 +1,25 @@
+from django.contrib.auth import LOGIN_URL, REDIRECT_FIELD_NAME
+from django.http import HttpResponseRedirect
+
+def user_passes_test(test_func, login_url=LOGIN_URL):
+ """
+ Decorator for views that checks that the user passes the given test,
+ redirecting to the log-in page if necessary. The test should be a callable
+ that takes the user object and returns True if the user passes.
+ """
+ def _dec(view_func):
+ def _checklogin(request, *args, **kwargs):
+ if test_func(request.user):
+ return view_func(request, *args, **kwargs)
+ return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, request.path))
+
+ return _checklogin
+ return _dec
+
+login_required = user_passes_test(lambda u: not u.is_anonymous())
+login_required.__doc__ = (
+ """
+ Decorator for views that checks that the user is logged in, redirecting
+ to the log-in page if necessary.
+ """
+ )
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
new file mode 100644
index 0000000000..6c0c8abe97
--- /dev/null
+++ b/django/contrib/auth/forms.py
@@ -0,0 +1,108 @@
+from django.contrib.auth.models import User
+from django.contrib.sites.models import Site
+from django.template import Context, loader
+from django.core import validators
+from django import forms
+
+class AuthenticationForm(forms.Manipulator):
+ """
+ Base class for authenticating users. Extend this to get a form that accepts
+ username/password logins.
+ """
+ def __init__(self, request=None):
+ """
+ If request is passed in, the manipulator will validate that cookies are
+ enabled. Note that the request (a HttpRequest object) must have set a
+ cookie with the key TEST_COOKIE_NAME and value TEST_COOKIE_VALUE before
+ running this validator.
+ """
+ self.request = request
+ self.fields = [
+ forms.TextField(field_name="username", length=15, maxlength=30, is_required=True,
+ validator_list=[self.isValidUser, self.hasCookiesEnabled]),
+ forms.PasswordField(field_name="password", length=15, maxlength=30, is_required=True,
+ validator_list=[self.isValidPasswordForUser]),
+ ]
+ self.user_cache = None
+
+ def hasCookiesEnabled(self, field_data, all_data):
+ if self.request and not self.request.session.test_cookie_worked():
+ raise validators.ValidationError, _("Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in.")
+
+ def isValidUser(self, field_data, all_data):
+ try:
+ self.user_cache = User.objects.get(username=field_data)
+ except User.DoesNotExist:
+ raise validators.ValidationError, _("Please enter a correct username and password. Note that both fields are case-sensitive.")
+
+ def isValidPasswordForUser(self, field_data, all_data):
+ if self.user_cache is not None and not self.user_cache.check_password(field_data):
+ self.user_cache = None
+ raise validators.ValidationError, _("Please enter a correct username and password. Note that both fields are case-sensitive.")
+
+ def get_user_id(self):
+ if self.user_cache:
+ return self.user_cache.id
+ return None
+
+ def get_user(self):
+ return self.user_cache
+
+class PasswordResetForm(forms.Manipulator):
+ "A form that lets a user request a password reset"
+ def __init__(self):
+ self.fields = (
+ forms.EmailField(field_name="email", length=40, is_required=True,
+ validator_list=[self.isValidUserEmail]),
+ )
+
+ def isValidUserEmail(self, new_data, all_data):
+ "Validates that a user exists with the given e-mail address"
+ try:
+ self.user_cache = User.objects.get(email__iexact=new_data)
+ except User.DoesNotExist:
+ raise validators.ValidationError, "That e-mail address doesn't have an associated user acount. Are you sure you've registered?"
+
+ def save(self, domain_override=None):
+ "Calculates a new password randomly and sends it to the user"
+ from django.core.mail import send_mail
+ new_pass = User.objects.make_random_password()
+ self.user_cache.set_password(new_pass)
+ self.user_cache.save()
+ if not domain_override:
+ current_site = Site.objects.get_current()
+ site_name = current_site.name
+ domain = current_site.domain
+ else:
+ site_name = domain = domain_override
+ t = loader.get_template('registration/password_reset_email.html')
+ c = {
+ 'new_password': new_pass,
+ 'email': self.user_cache.email,
+ 'domain': domain,
+ 'site_name': site_name,
+ 'user': self.user_cache,
+ }
+ send_mail('Password reset on %s' % site_name, t.render(Context(c)), None, [self.user_cache.email])
+
+class PasswordChangeForm(forms.Manipulator):
+ "A form that lets a user change his password."
+ def __init__(self, user):
+ self.user = user
+ self.fields = (
+ forms.PasswordField(field_name="old_password", length=30, maxlength=30, is_required=True,
+ validator_list=[self.isValidOldPassword]),
+ forms.PasswordField(field_name="new_password1", length=30, maxlength=30, is_required=True,
+ validator_list=[validators.AlwaysMatchesOtherField('new_password2', "The two 'new password' fields didn't match.")]),
+ forms.PasswordField(field_name="new_password2", length=30, maxlength=30, is_required=True),
+ )
+
+ def isValidOldPassword(self, new_data, all_data):
+ "Validates that the old_password field is correct."
+ if not self.user.check_password(new_data):
+ raise validators.ValidationError, "Your old password was entered incorrectly. Please enter it again."
+
+ def save(self, new_data):
+ "Saves the new password."
+ self.user.set_password(new_data['new_password1'])
+ self.user.save()
diff --git a/django/contrib/auth/handlers/modpython.py b/django/contrib/auth/handlers/modpython.py
index d538c9ccc8..b1d7680a33 100644
--- a/django/contrib/auth/handlers/modpython.py
+++ b/django/contrib/auth/handlers/modpython.py
@@ -10,7 +10,7 @@ def authenhandler(req, **kwargs):
# that so that the following import works
os.environ.update(req.subprocess_env)
- from django.models.auth import users
+ from django.contrib.auth.models import User
# check for PythonOptions
_str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
@@ -21,14 +21,14 @@ def authenhandler(req, **kwargs):
superuser_only = _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off"))
# check that the username is valid
- kwargs = {'username__exact': req.user, 'is_active__exact': True}
+ kwargs = {'username': req.user, 'is_active': True}
if staff_only:
- kwargs['is_staff__exact'] = True
+ kwargs['is_staff'] = True
if superuser_only:
- kwargs['is_superuser__exact'] = True
+ kwargs['is_superuser'] = True
try:
- user = users.get_object(**kwargs)
- except users.UserDoesNotExist:
+ user = User.objects.get(**kwargs)
+ except User.DoesNotExist:
return apache.HTTP_UNAUTHORIZED
# check the password and any permission given
diff --git a/django/contrib/auth/management.py b/django/contrib/auth/management.py
new file mode 100644
index 0000000000..fe3399edbb
--- /dev/null
+++ b/django/contrib/auth/management.py
@@ -0,0 +1,53 @@
+"""
+Creates permissions for all installed apps that need permissions.
+"""
+
+from django.dispatch import dispatcher
+from django.db.models import get_models, signals
+from django.contrib.auth import models as auth_app
+
+def _get_permission_codename(action, opts):
+ return '%s_%s' % (action, opts.object_name.lower())
+
+def _get_all_permissions(opts):
+ "Returns (codename, name) for all permissions in the given opts."
+ perms = []
+ for action in ('add', 'change', 'delete'):
+ perms.append((_get_permission_codename(action, opts), 'Can %s %s' % (action, opts.verbose_name)))
+ return perms + list(opts.permissions)
+
+def create_permissions(app, created_models):
+ from django.contrib.contenttypes.models import ContentType
+ from django.contrib.auth.models import Permission
+ app_models = get_models(app)
+ if not app_models:
+ return
+ for klass in app_models:
+ if not klass._meta.admin:
+ continue
+ ctype = ContentType.objects.get_for_model(klass)
+ for codename, name in _get_all_permissions(klass._meta):
+ try:
+ Permission.objects.get(name=name, codename=codename, content_type__pk=ctype.id)
+ except Permission.DoesNotExist:
+ p = Permission(name=name, codename=codename, content_type=ctype)
+ p.save()
+ print "Adding permission '%s'" % p
+
+def create_superuser(app, created_models):
+ from django.contrib.auth.models import User
+ from django.contrib.auth.create_superuser import createsuperuser as do_create
+ if User in created_models:
+ msg = "\nYou just installed Django's auth system, which means you don't have " \
+ "any superusers defined.\nWould you like to create one now? (yes/no): "
+ confirm = raw_input(msg)
+ while 1:
+ if confirm not in ('yes', 'no'):
+ confirm = raw_input('Please enter either "yes" or "no": ')
+ continue
+ if confirm == 'yes':
+ do_create()
+ break
+
+dispatcher.connect(create_permissions, signal=signals.post_syncdb)
+dispatcher.connect(create_superuser, sender=auth_app, signal=signals.post_syncdb)
diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py
new file mode 100644
index 0000000000..4b3ed54960
--- /dev/null
+++ b/django/contrib/auth/middleware.py
@@ -0,0 +1,19 @@
+class LazyUser(object):
+ def __init__(self):
+ self._user = None
+
+ def __get__(self, request, obj_type=None):
+ if self._user is None:
+ from django.contrib.auth.models import User, AnonymousUser, SESSION_KEY
+ try:
+ user_id = request.session[SESSION_KEY]
+ self._user = User.objects.get(pk=user_id)
+ except (KeyError, User.DoesNotExist):
+ self._user = AnonymousUser()
+ return self._user
+
+class AuthenticationMiddleware:
+ def process_request(self, request):
+ assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
+ request.__class__.user = LazyUser()
+ return None
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
new file mode 100644
index 0000000000..cea7a694c9
--- /dev/null
+++ b/django/contrib/auth/models.py
@@ -0,0 +1,264 @@
+from django.core import validators
+from django.db import backend, connection, models
+from django.contrib.contenttypes.models import ContentType
+from django.utils.translation import gettext_lazy as _
+import datetime
+
+SESSION_KEY = '_auth_user_id'
+
+class SiteProfileNotAvailable(Exception):
+ pass
+
+class Permission(models.Model):
+ name = models.CharField(_('name'), maxlength=50)
+ content_type = models.ForeignKey(ContentType)
+ codename = models.CharField(_('codename'), maxlength=100)
+ class Meta:
+ verbose_name = _('permission')
+ verbose_name_plural = _('permissions')
+ unique_together = (('content_type', 'codename'),)
+ ordering = ('content_type', 'codename')
+
+ def __str__(self):
+ return "%r | %s" % (self.content_type, self.name)
+
+class Group(models.Model):
+ name = models.CharField(_('name'), maxlength=80, unique=True)
+ permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True, filter_interface=models.HORIZONTAL)
+ class Meta:
+ verbose_name = _('group')
+ verbose_name_plural = _('groups')
+ ordering = ('name',)
+ class Admin:
+ search_fields = ('name',)
+
+ def __str__(self):
+ return self.name
+
+class UserManager(models.Manager):
+ def create_user(self, username, email, password):
+ "Creates and saves a User with the given username, e-mail and password."
+ now = datetime.datetime.now()
+ user = self.model(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now)
+ user.set_password(password)
+ user.save()
+ return user
+
+ def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
+ "Generates a random password with the given length and given allowed_chars"
+ # Note that default value of allowed_chars does not have "I" or letters
+ # that look like it -- just to avoid confusion.
+ from random import choice
+ return ''.join([choice(allowed_chars) for i in range(length)])
+
+class User(models.Model):
+ username = models.CharField(_('username'), maxlength=30, unique=True, validator_list=[validators.isAlphaNumeric])
+ first_name = models.CharField(_('first name'), maxlength=30, blank=True)
+ last_name = models.CharField(_('last name'), maxlength=30, blank=True)
+ email = models.EmailField(_('e-mail address'), blank=True)
+ password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]'"))
+ is_staff = models.BooleanField(_('staff status'), help_text=_("Designates whether the user can log into this admin site."))
+ is_active = models.BooleanField(_('active'), default=True)
+ is_superuser = models.BooleanField(_('superuser status'))
+ last_login = models.DateTimeField(_('last login'), default=models.LazyDate())
+ date_joined = models.DateTimeField(_('date joined'), default=models.LazyDate())
+ groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
+ help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
+ user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, filter_interface=models.HORIZONTAL)
+ objects = UserManager()
+ class Meta:
+ verbose_name = _('user')
+ verbose_name_plural = _('users')
+ ordering = ('username',)
+ class Admin:
+ fields = (
+ (None, {'fields': ('username', 'password')}),
+ (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
+ (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
+ (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
+ (_('Groups'), {'fields': ('groups',)}),
+ )
+ list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
+ list_filter = ('is_staff', 'is_superuser')
+ search_fields = ('username', 'first_name', 'last_name', 'email')
+
+ def __str__(self):
+ return self.username
+
+ def get_absolute_url(self):
+ return "/users/%s/" % self.username
+
+ def is_anonymous(self):
+ return False
+
+ def get_full_name(self):
+ full_name = '%s %s' % (self.first_name, self.last_name)
+ return full_name.strip()
+
+ def set_password(self, raw_password):
+ import sha, random
+ algo = 'sha1'
+ salt = sha.new(str(random.random())).hexdigest()[:5]
+ hsh = sha.new(salt+raw_password).hexdigest()
+ self.password = '%s$%s$%s' % (algo, salt, hsh)
+
+ def check_password(self, raw_password):
+ """
+ Returns a boolean of whether the raw_password was correct. Handles
+ encryption formats behind the scenes.
+ """
+ # Backwards-compatibility check. Older passwords won't include the
+ # algorithm or salt.
+ if '$' not in self.password:
+ import md5
+ is_correct = (self.password == md5.new(raw_password).hexdigest())
+ if is_correct:
+ # Convert the password to the new, more secure format.
+ self.set_password(raw_password)
+ self.save()
+ return is_correct
+ algo, salt, hsh = self.password.split('$')
+ if algo == 'md5':
+ import md5
+ return hsh == md5.new(salt+raw_password).hexdigest()
+ elif algo == 'sha1':
+ import sha
+ return hsh == sha.new(salt+raw_password).hexdigest()
+ raise ValueError, "Got unknown password algorithm type in password."
+
+ def get_group_permissions(self):
+ "Returns a list of permission strings that this user has through his/her groups."
+ if not hasattr(self, '_group_perm_cache'):
+ import sets
+ cursor = connection.cursor()
+ # The SQL below works out to the following, after DB quoting:
+ # cursor.execute("""
+ # SELECT ct."app_label", p."codename"
+ # FROM "auth_permission" p, "auth_group_permissions" gp, "auth_user_groups" ug, "django_content_type" ct
+ # WHERE p."id" = gp."permission_id"
+ # AND gp."group_id" = ug."group_id"
+ # AND ct."id" = p."content_type_id"
+ # AND ug."user_id" = %s, [self.id])
+ sql = """
+ SELECT ct.%s, p.%s
+ FROM %s p, %s gp, %s ug, %s ct
+ WHERE p.%s = gp.%s
+ AND gp.%s = ug.%s
+ AND ct.%s = p.%s
+ AND ug.%s = %%s""" % (
+ backend.quote_name('app_label'), backend.quote_name('codename'),
+ backend.quote_name('auth_permission'), backend.quote_name('auth_group_permissions'),
+ backend.quote_name('auth_user_groups'), backend.quote_name('django_content_type'),
+ backend.quote_name('id'), backend.quote_name('permission_id'),
+ backend.quote_name('group_id'), backend.quote_name('group_id'),
+ backend.quote_name('id'), backend.quote_name('content_type_id'),
+ backend.quote_name('user_id'),)
+ cursor.execute(sql, [self.id])
+ self._group_perm_cache = sets.Set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
+ return self._group_perm_cache
+
+ def get_all_permissions(self):
+ if not hasattr(self, '_perm_cache'):
+ import sets
+ self._perm_cache = sets.Set(["%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.all()])
+ self._perm_cache.update(self.get_group_permissions())
+ return self._perm_cache
+
+ def has_perm(self, perm):
+ "Returns True if the user has the specified permission."
+ if not self.is_active:
+ return False
+ if self.is_superuser:
+ return True
+ return perm in self.get_all_permissions()
+
+ def has_perms(self, perm_list):
+ "Returns True if the user has each of the specified permissions."
+ for perm in perm_list:
+ if not self.has_perm(perm):
+ return False
+ return True
+
+ def has_module_perms(self, app_label):
+ "Returns True if the user has any permissions in the given app label."
+ if self.is_superuser:
+ return True
+ return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label]))
+
+ def get_and_delete_messages(self):
+ messages = []
+ for m in self.message_set.all():
+ messages.append(m.message)
+ m.delete()
+ return messages
+
+ def email_user(self, subject, message, from_email=None):
+ "Sends an e-mail to this User."
+ from django.core.mail import send_mail
+ send_mail(subject, message, from_email, [self.email])
+
+ def get_profile(self):
+ """
+ Returns site-specific profile for this user. Raises
+ SiteProfileNotAvailable if this site does not allow profiles.
+ """
+ if not hasattr(self, '_profile_cache'):
+ from django.conf import settings
+ if not settings.AUTH_PROFILE_MODULE:
+ raise SiteProfileNotAvailable
+ try:
+ app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
+ model = models.get_model(app_label, model_name)
+ self._profile_cache = model._default_manager.get(user__id__exact=self.id)
+ except ImportError, ImproperlyConfigured:
+ raise SiteProfileNotAvailable
+ return self._profile_cache
+
+class Message(models.Model):
+ user = models.ForeignKey(User)
+ message = models.TextField(_('message'))
+
+ def __str__(self):
+ return self.message
+
+class AnonymousUser(object):
+ id = None
+ username = ''
+
+ def __init__(self):
+ pass
+
+ def __str__(self):
+ return 'AnonymousUser'
+
+ def save(self):
+ raise NotImplementedError
+
+ def delete(self):
+ raise NotImplementedError
+
+ def set_password(self, raw_password):
+ raise NotImplementedError
+
+ def check_password(self, raw_password):
+ raise NotImplementedError
+
+ def _get_groups(self):
+ raise NotImplementedError
+ groups = property(_get_groups)
+
+ def _get_user_permissions(self):
+ raise NotImplementedError
+ user_permissions = property(_get_user_permissions)
+
+ def has_perm(self, perm):
+ return False
+
+ def has_module_perms(self, module):
+ return False
+
+ def get_and_delete_messages(self):
+ return []
+
+ def is_anonymous(self):
+ return True
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
new file mode 100644
index 0000000000..f919f82419
--- /dev/null
+++ b/django/contrib/auth/views.py
@@ -0,0 +1,84 @@
+from django.contrib.auth.forms import AuthenticationForm
+from django.contrib.auth.forms import PasswordResetForm, PasswordChangeForm
+from django import forms
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.contrib.auth.models import SESSION_KEY
+from django.contrib.sites.models import Site
+from django.http import HttpResponse, HttpResponseRedirect
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth import LOGIN_URL, REDIRECT_FIELD_NAME
+
+def login(request):
+ "Displays the login form and handles the login action."
+ manipulator = AuthenticationForm(request)
+ redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '')
+ if request.POST:
+ errors = manipulator.get_validation_errors(request.POST)
+ if not errors:
+ # Light security check -- make sure redirect_to isn't garbage.
+ if not redirect_to or '://' in redirect_to or ' ' in redirect_to:
+ redirect_to = '/accounts/profile/'
+ request.session[SESSION_KEY] = manipulator.get_user_id()
+ request.session.delete_test_cookie()
+ return HttpResponseRedirect(redirect_to)
+ else:
+ errors = {}
+ request.session.set_test_cookie()
+ return render_to_response('registration/login.html', {
+ 'form': forms.FormWrapper(manipulator, request.POST, errors),
+ REDIRECT_FIELD_NAME: redirect_to,
+ 'site_name': Site.objects.get_current().name,
+ }, context_instance=RequestContext(request))
+
+def logout(request, next_page=None):
+ "Logs out the user and displays 'You are logged out' message."
+ try:
+ del request.session[SESSION_KEY]
+ except KeyError:
+ return render_to_response('registration/logged_out.html', {'title': 'Logged out'}, context_instance=RequestContext(request))
+ else:
+ # Redirect to this page until the session has been cleared.
+ return HttpResponseRedirect(next_page or request.path)
+
+def logout_then_login(request, login_url=LOGIN_URL):
+ "Logs out the user if he is logged in. Then redirects to the log-in page."
+ return logout(request, login_url)
+
+def redirect_to_login(next, login_url=LOGIN_URL):
+ "Redirects the user to the login page, passing the given 'next' page"
+ return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, next))
+
+def password_reset(request, is_admin_site=False):
+ new_data, errors = {}, {}
+ form = PasswordResetForm()
+ if request.POST:
+ new_data = request.POST.copy()
+ errors = form.get_validation_errors(new_data)
+ if not errors:
+ if is_admin_site:
+ form.save(request.META['HTTP_HOST'])
+ else:
+ form.save()
+ return HttpResponseRedirect('%sdone/' % request.path)
+ return render_to_response('registration/password_reset_form.html', {'form': forms.FormWrapper(form, new_data, errors)},
+ context_instance=RequestContext(request))
+
+def password_reset_done(request):
+ return render_to_response('registration/password_reset_done.html', context_instance=RequestContext(request))
+
+def password_change(request):
+ new_data, errors = {}, {}
+ form = PasswordChangeForm(request.user)
+ if request.POST:
+ new_data = request.POST.copy()
+ errors = form.get_validation_errors(new_data)
+ if not errors:
+ form.save(new_data)
+ return HttpResponseRedirect('%sdone/' % request.path)
+ return render_to_response('registration/password_change_form.html', {'form': forms.FormWrapper(form, new_data, errors)},
+ context_instance=RequestContext(request))
+password_change = login_required(password_change)
+
+def password_change_done(request):
+ return render_to_response('registration/password_change_done.html', context_instance=RequestContext(request))