OLD | NEW |
(Empty) | |
| 1 from __future__ import unicode_literals |
| 2 |
| 3 from django.contrib import auth |
| 4 from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager |
| 5 from django.contrib.auth.signals import user_logged_in |
| 6 from django.contrib.contenttypes.models import ContentType |
| 7 from django.core.exceptions import PermissionDenied |
| 8 from django.core.mail import send_mail |
| 9 from django.db import models |
| 10 from django.db.models.manager import EmptyManager |
| 11 from django.utils import six, timezone |
| 12 from django.utils.deprecation import CallableFalse, CallableTrue |
| 13 from django.utils.encoding import python_2_unicode_compatible |
| 14 from django.utils.translation import ugettext_lazy as _ |
| 15 |
| 16 from .validators import ASCIIUsernameValidator, UnicodeUsernameValidator |
| 17 |
| 18 |
| 19 def update_last_login(sender, user, **kwargs): |
| 20 """ |
| 21 A signal receiver which updates the last_login date for |
| 22 the user logging in. |
| 23 """ |
| 24 user.last_login = timezone.now() |
| 25 user.save(update_fields=['last_login']) |
| 26 |
| 27 |
| 28 user_logged_in.connect(update_last_login) |
| 29 |
| 30 |
| 31 class PermissionManager(models.Manager): |
| 32 use_in_migrations = True |
| 33 |
| 34 def get_by_natural_key(self, codename, app_label, model): |
| 35 return self.get( |
| 36 codename=codename, |
| 37 content_type=ContentType.objects.db_manager(self.db).get_by_natural_
key(app_label, model), |
| 38 ) |
| 39 |
| 40 |
| 41 @python_2_unicode_compatible |
| 42 class Permission(models.Model): |
| 43 """ |
| 44 The permissions system provides a way to assign permissions to specific |
| 45 users and groups of users. |
| 46 |
| 47 The permission system is used by the Django admin site, but may also be |
| 48 useful in your own code. The Django admin site uses permissions as follows: |
| 49 |
| 50 - The "add" permission limits the user's ability to view the "add" form |
| 51 and add an object. |
| 52 - The "change" permission limits a user's ability to view the change |
| 53 list, view the "change" form and change an object. |
| 54 - The "delete" permission limits the ability to delete an object. |
| 55 |
| 56 Permissions are set globally per type of object, not per specific object |
| 57 instance. It is possible to say "Mary may change news stories," but it's |
| 58 not currently possible to say "Mary may change news stories, but only the |
| 59 ones she created herself" or "Mary may only change news stories that have a |
| 60 certain status or publication date." |
| 61 |
| 62 Three basic permissions -- add, change and delete -- are automatically |
| 63 created for each Django model. |
| 64 """ |
| 65 name = models.CharField(_('name'), max_length=255) |
| 66 content_type = models.ForeignKey( |
| 67 ContentType, |
| 68 models.CASCADE, |
| 69 verbose_name=_('content type'), |
| 70 ) |
| 71 codename = models.CharField(_('codename'), max_length=100) |
| 72 objects = PermissionManager() |
| 73 |
| 74 class Meta: |
| 75 verbose_name = _('permission') |
| 76 verbose_name_plural = _('permissions') |
| 77 unique_together = (('content_type', 'codename'),) |
| 78 ordering = ('content_type__app_label', 'content_type__model', |
| 79 'codename') |
| 80 |
| 81 def __str__(self): |
| 82 return "%s | %s | %s" % ( |
| 83 six.text_type(self.content_type.app_label), |
| 84 six.text_type(self.content_type), |
| 85 six.text_type(self.name)) |
| 86 |
| 87 def natural_key(self): |
| 88 return (self.codename,) + self.content_type.natural_key() |
| 89 natural_key.dependencies = ['contenttypes.contenttype'] |
| 90 |
| 91 |
| 92 class GroupManager(models.Manager): |
| 93 """ |
| 94 The manager for the auth's Group model. |
| 95 """ |
| 96 use_in_migrations = True |
| 97 |
| 98 def get_by_natural_key(self, name): |
| 99 return self.get(name=name) |
| 100 |
| 101 |
| 102 @python_2_unicode_compatible |
| 103 class Group(models.Model): |
| 104 """ |
| 105 Groups are a generic way of categorizing users to apply permissions, or |
| 106 some other label, to those users. A user can belong to any number of |
| 107 groups. |
| 108 |
| 109 A user in a group automatically has all the permissions granted to that |
| 110 group. For example, if the group 'Site editors' has the permission |
| 111 can_edit_home_page, any user in that group will have that permission. |
| 112 |
| 113 Beyond permissions, groups are a convenient way to categorize users to |
| 114 apply some label, or extended functionality, to them. For example, you |
| 115 could create a group 'Special users', and you could write code that would |
| 116 do special things to those users -- such as giving them access to a |
| 117 members-only portion of your site, or sending them members-only email |
| 118 messages. |
| 119 """ |
| 120 name = models.CharField(_('name'), max_length=80, unique=True) |
| 121 permissions = models.ManyToManyField( |
| 122 Permission, |
| 123 verbose_name=_('permissions'), |
| 124 blank=True, |
| 125 ) |
| 126 |
| 127 objects = GroupManager() |
| 128 |
| 129 class Meta: |
| 130 verbose_name = _('group') |
| 131 verbose_name_plural = _('groups') |
| 132 |
| 133 def __str__(self): |
| 134 return self.name |
| 135 |
| 136 def natural_key(self): |
| 137 return (self.name,) |
| 138 |
| 139 |
| 140 class UserManager(BaseUserManager): |
| 141 use_in_migrations = True |
| 142 |
| 143 def _create_user(self, username, email, password, **extra_fields): |
| 144 """ |
| 145 Creates and saves a User with the given username, email and password. |
| 146 """ |
| 147 if not username: |
| 148 raise ValueError('The given username must be set') |
| 149 email = self.normalize_email(email) |
| 150 username = self.model.normalize_username(username) |
| 151 user = self.model(username=username, email=email, **extra_fields) |
| 152 user.set_password(password) |
| 153 user.save(using=self._db) |
| 154 return user |
| 155 |
| 156 def create_user(self, username, email=None, password=None, **extra_fields): |
| 157 extra_fields.setdefault('is_staff', False) |
| 158 extra_fields.setdefault('is_superuser', False) |
| 159 return self._create_user(username, email, password, **extra_fields) |
| 160 |
| 161 def create_superuser(self, username, email, password, **extra_fields): |
| 162 extra_fields.setdefault('is_staff', True) |
| 163 extra_fields.setdefault('is_superuser', True) |
| 164 |
| 165 if extra_fields.get('is_staff') is not True: |
| 166 raise ValueError('Superuser must have is_staff=True.') |
| 167 if extra_fields.get('is_superuser') is not True: |
| 168 raise ValueError('Superuser must have is_superuser=True.') |
| 169 |
| 170 return self._create_user(username, email, password, **extra_fields) |
| 171 |
| 172 |
| 173 # A few helper functions for common logic between User and AnonymousUser. |
| 174 def _user_get_all_permissions(user, obj): |
| 175 permissions = set() |
| 176 for backend in auth.get_backends(): |
| 177 if hasattr(backend, "get_all_permissions"): |
| 178 permissions.update(backend.get_all_permissions(user, obj)) |
| 179 return permissions |
| 180 |
| 181 |
| 182 def _user_has_perm(user, perm, obj): |
| 183 """ |
| 184 A backend can raise `PermissionDenied` to short-circuit permission checking. |
| 185 """ |
| 186 for backend in auth.get_backends(): |
| 187 if not hasattr(backend, 'has_perm'): |
| 188 continue |
| 189 try: |
| 190 if backend.has_perm(user, perm, obj): |
| 191 return True |
| 192 except PermissionDenied: |
| 193 return False |
| 194 return False |
| 195 |
| 196 |
| 197 def _user_has_module_perms(user, app_label): |
| 198 """ |
| 199 A backend can raise `PermissionDenied` to short-circuit permission checking. |
| 200 """ |
| 201 for backend in auth.get_backends(): |
| 202 if not hasattr(backend, 'has_module_perms'): |
| 203 continue |
| 204 try: |
| 205 if backend.has_module_perms(user, app_label): |
| 206 return True |
| 207 except PermissionDenied: |
| 208 return False |
| 209 return False |
| 210 |
| 211 |
| 212 class PermissionsMixin(models.Model): |
| 213 """ |
| 214 A mixin class that adds the fields and methods necessary to support |
| 215 Django's Group and Permission model using the ModelBackend. |
| 216 """ |
| 217 is_superuser = models.BooleanField( |
| 218 _('superuser status'), |
| 219 default=False, |
| 220 help_text=_( |
| 221 'Designates that this user has all permissions without ' |
| 222 'explicitly assigning them.' |
| 223 ), |
| 224 ) |
| 225 groups = models.ManyToManyField( |
| 226 Group, |
| 227 verbose_name=_('groups'), |
| 228 blank=True, |
| 229 help_text=_( |
| 230 'The groups this user belongs to. A user will get all permissions ' |
| 231 'granted to each of their groups.' |
| 232 ), |
| 233 related_name="user_set", |
| 234 related_query_name="user", |
| 235 ) |
| 236 user_permissions = models.ManyToManyField( |
| 237 Permission, |
| 238 verbose_name=_('user permissions'), |
| 239 blank=True, |
| 240 help_text=_('Specific permissions for this user.'), |
| 241 related_name="user_set", |
| 242 related_query_name="user", |
| 243 ) |
| 244 |
| 245 class Meta: |
| 246 abstract = True |
| 247 |
| 248 def get_group_permissions(self, obj=None): |
| 249 """ |
| 250 Returns a list of permission strings that this user has through their |
| 251 groups. This method queries all available auth backends. If an object |
| 252 is passed in, only permissions matching this object are returned. |
| 253 """ |
| 254 permissions = set() |
| 255 for backend in auth.get_backends(): |
| 256 if hasattr(backend, "get_group_permissions"): |
| 257 permissions.update(backend.get_group_permissions(self, obj)) |
| 258 return permissions |
| 259 |
| 260 def get_all_permissions(self, obj=None): |
| 261 return _user_get_all_permissions(self, obj) |
| 262 |
| 263 def has_perm(self, perm, obj=None): |
| 264 """ |
| 265 Returns True if the user has the specified permission. This method |
| 266 queries all available auth backends, but returns immediately if any |
| 267 backend returns True. Thus, a user who has permission from a single |
| 268 auth backend is assumed to have permission in general. If an object is |
| 269 provided, permissions for this specific object are checked. |
| 270 """ |
| 271 |
| 272 # Active superusers have all permissions. |
| 273 if self.is_active and self.is_superuser: |
| 274 return True |
| 275 |
| 276 # Otherwise we need to check the backends. |
| 277 return _user_has_perm(self, perm, obj) |
| 278 |
| 279 def has_perms(self, perm_list, obj=None): |
| 280 """ |
| 281 Returns True if the user has each of the specified permissions. If |
| 282 object is passed, it checks if the user has all required perms for this |
| 283 object. |
| 284 """ |
| 285 return all(self.has_perm(perm, obj) for perm in perm_list) |
| 286 |
| 287 def has_module_perms(self, app_label): |
| 288 """ |
| 289 Returns True if the user has any permissions in the given app label. |
| 290 Uses pretty much the same logic as has_perm, above. |
| 291 """ |
| 292 # Active superusers have all permissions. |
| 293 if self.is_active and self.is_superuser: |
| 294 return True |
| 295 |
| 296 return _user_has_module_perms(self, app_label) |
| 297 |
| 298 |
| 299 class AbstractUser(AbstractBaseUser, PermissionsMixin): |
| 300 """ |
| 301 An abstract base class implementing a fully featured User model with |
| 302 admin-compliant permissions. |
| 303 |
| 304 Username and password are required. Other fields are optional. |
| 305 """ |
| 306 username_validator = UnicodeUsernameValidator() if six.PY3 else ASCIIUsernam
eValidator() |
| 307 |
| 308 username = models.CharField( |
| 309 _('username'), |
| 310 max_length=150, |
| 311 unique=True, |
| 312 help_text=_('Required. 150 characters or fewer. Letters, digits and @/./
+/-/_ only.'), |
| 313 validators=[username_validator], |
| 314 error_messages={ |
| 315 'unique': _("A user with that username already exists."), |
| 316 }, |
| 317 ) |
| 318 first_name = models.CharField(_('first name'), max_length=30, blank=True) |
| 319 last_name = models.CharField(_('last name'), max_length=30, blank=True) |
| 320 email = models.EmailField(_('email address'), blank=True) |
| 321 is_staff = models.BooleanField( |
| 322 _('staff status'), |
| 323 default=False, |
| 324 help_text=_('Designates whether the user can log into this admin site.')
, |
| 325 ) |
| 326 is_active = models.BooleanField( |
| 327 _('active'), |
| 328 default=True, |
| 329 help_text=_( |
| 330 'Designates whether this user should be treated as active. ' |
| 331 'Unselect this instead of deleting accounts.' |
| 332 ), |
| 333 ) |
| 334 date_joined = models.DateTimeField(_('date joined'), default=timezone.now) |
| 335 |
| 336 objects = UserManager() |
| 337 |
| 338 EMAIL_FIELD = 'email' |
| 339 USERNAME_FIELD = 'username' |
| 340 REQUIRED_FIELDS = ['email'] |
| 341 |
| 342 class Meta: |
| 343 verbose_name = _('user') |
| 344 verbose_name_plural = _('users') |
| 345 abstract = True |
| 346 |
| 347 def clean(self): |
| 348 super(AbstractUser, self).clean() |
| 349 self.email = self.__class__.objects.normalize_email(self.email) |
| 350 |
| 351 def get_full_name(self): |
| 352 """ |
| 353 Returns the first_name plus the last_name, with a space in between. |
| 354 """ |
| 355 full_name = '%s %s' % (self.first_name, self.last_name) |
| 356 return full_name.strip() |
| 357 |
| 358 def get_short_name(self): |
| 359 "Returns the short name for the user." |
| 360 return self.first_name |
| 361 |
| 362 def email_user(self, subject, message, from_email=None, **kwargs): |
| 363 """ |
| 364 Sends an email to this User. |
| 365 """ |
| 366 send_mail(subject, message, from_email, [self.email], **kwargs) |
| 367 |
| 368 |
| 369 class User(AbstractUser): |
| 370 """ |
| 371 Users within the Django authentication system are represented by this |
| 372 model. |
| 373 |
| 374 Username, password and email are required. Other fields are optional. |
| 375 """ |
| 376 class Meta(AbstractUser.Meta): |
| 377 swappable = 'AUTH_USER_MODEL' |
| 378 |
| 379 |
| 380 @python_2_unicode_compatible |
| 381 class AnonymousUser(object): |
| 382 id = None |
| 383 pk = None |
| 384 username = '' |
| 385 is_staff = False |
| 386 is_active = False |
| 387 is_superuser = False |
| 388 _groups = EmptyManager(Group) |
| 389 _user_permissions = EmptyManager(Permission) |
| 390 |
| 391 def __init__(self): |
| 392 pass |
| 393 |
| 394 def __str__(self): |
| 395 return 'AnonymousUser' |
| 396 |
| 397 def __eq__(self, other): |
| 398 return isinstance(other, self.__class__) |
| 399 |
| 400 def __ne__(self, other): |
| 401 return not self.__eq__(other) |
| 402 |
| 403 def __hash__(self): |
| 404 return 1 # instances always return the same hash value |
| 405 |
| 406 def save(self): |
| 407 raise NotImplementedError("Django doesn't provide a DB representation fo
r AnonymousUser.") |
| 408 |
| 409 def delete(self): |
| 410 raise NotImplementedError("Django doesn't provide a DB representation fo
r AnonymousUser.") |
| 411 |
| 412 def set_password(self, raw_password): |
| 413 raise NotImplementedError("Django doesn't provide a DB representation fo
r AnonymousUser.") |
| 414 |
| 415 def check_password(self, raw_password): |
| 416 raise NotImplementedError("Django doesn't provide a DB representation fo
r AnonymousUser.") |
| 417 |
| 418 @property |
| 419 def groups(self): |
| 420 return self._groups |
| 421 |
| 422 @property |
| 423 def user_permissions(self): |
| 424 return self._user_permissions |
| 425 |
| 426 def get_group_permissions(self, obj=None): |
| 427 return set() |
| 428 |
| 429 def get_all_permissions(self, obj=None): |
| 430 return _user_get_all_permissions(self, obj=obj) |
| 431 |
| 432 def has_perm(self, perm, obj=None): |
| 433 return _user_has_perm(self, perm, obj=obj) |
| 434 |
| 435 def has_perms(self, perm_list, obj=None): |
| 436 for perm in perm_list: |
| 437 if not self.has_perm(perm, obj): |
| 438 return False |
| 439 return True |
| 440 |
| 441 def has_module_perms(self, module): |
| 442 return _user_has_module_perms(self, module) |
| 443 |
| 444 @property |
| 445 def is_anonymous(self): |
| 446 return CallableTrue |
| 447 |
| 448 @property |
| 449 def is_authenticated(self): |
| 450 return CallableFalse |
| 451 |
| 452 def get_username(self): |
| 453 return self.username |
OLD | NEW |