2006-05-02 09:31:56 +08:00
|
|
|
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):
|
2006-06-01 11:33:34 +08:00
|
|
|
return "%s | %s" % (self.content_type, self.name)
|
2006-05-02 09:31:56 +08:00
|
|
|
|
|
|
|
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
|
2006-06-20 11:08:48 +08:00
|
|
|
self._perm_cache = sets.Set(["%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.select_related()])
|
2006-05-02 09:31:56 +08:00
|
|
|
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
|