permission.models: 96 total statements, 88.4% covered

Generated: Thu 2012-03-01 14:22 CST

Source file: /home/alisue/Dropbox/Codes/django-permission/permission/models.py

Stats: 76 executed, 10 missed, 10 excluded, 108 ignored

  1. # vim: set fileencoding=utf-8 :
  2. """
  3. Permission handler base
  4. AUTHOR:
  5. lambdalisue[Ali su ae] (lambdalisue@hashnote.net)
  6. License:
  7. The MIT License (MIT)
  8. Copyright (c) 2012 Alisue allright reserved.
  9. Permission is hereby granted, free of charge, to any person obtaining a copy
  10. of this software and associated documentation files (the "Software"), to
  11. deal in the Software without restriction, including without limitation the
  12. rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  13. sell copies of the Software, and to permit persons to whom the Software is
  14. furnished to do so, subject to the following conditions:
  15. The above copyright notice and this permission notice shall be included in
  16. all copies or substantial portions of the Software.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  23. IN THE SOFTWARE.
  24. """
  25. from __future__ import with_statement
  26. from django.db import models
  27. from django.contrib.auth.models import User
  28. from django.contrib.auth.models import Permission
  29. from django.utils.translation import ugettext_lazy as _
  30. from mptt.models import MPTTModel
  31. from mptt.models import TreeForeignKey
  32. from mptt.models import TreeManager
  33. class RoleManager(TreeManager):
  34. def get_by_natural_key(self, codename):
  35. return self.get(codename=codename)
  36. def filter_by_user(self, user_obj):
  37. """return queryset of roles which ``user_obj`` have"""
  38. # do not defer anything otherwise the returning queryset
  39. # contains defered instance.
  40. roles_qs = self.none()
  41. for role in self.filter(_users=user_obj).iterator():
  42. roles_qs |= role.get_descendants(include_self=True)
  43. return roles_qs
  44. def get_all_permissions_of_user(self, user_obj):
  45. """get a set of all permissions of ``user_obj``"""
  46. # name, parent, _users, _permissions are required.
  47. roles = self.defer('codename', 'description').filter(_users=user_obj)
  48. permissions = Permission.objects.none()
  49. for role in roles.iterator():
  50. permissions |= role.permissions
  51. return permissions.distinct()
  52. class Role(MPTTModel):
  53. """A role model for enhanced permission system."""
  54. name = models.CharField(_('name'), max_length=50)
  55. codename = models.CharField(_('codename'), max_length=100, unique=True)
  56. description = models.TextField(_('description'), blank=True,
  57. help_text=_('A description of this permission role'))
  58. parent = TreeForeignKey('self', verbose_name=_('parent role'),
  59. related_name='children', blank=True, null=True)
  60. _users = models.ManyToManyField(User, verbose_name=_('user'),
  61. related_name='_roles', db_column='users', blank=True)
  62. _permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'),
  63. related_name='roles', db_column='permissions', blank=True)
  64. objects = RoleManager()
  65. class Meta:
  66. verbose_name = _('role')
  67. verbose_name_plural = _('roles')
  68. class MPTTMeta:
  69. order_insertion_by = ['name']
  70. def __unicode__(self):
  71. return self.name
  72. def natural_key(self):
  73. return (self.codename,)
  74. @property
  75. def users(self):
  76. """get all users who belongs to this role or superroles"""
  77. role_pks = self.get_descendants(include_self=True).values_list('id', flat=True)
  78. qs = User.objects.only('id', '_roles').filter(_roles__pk__in=role_pks).distinct()
  79. return qs.defer(None)
  80. @property
  81. def permissions(self):
  82. """get all permissions which this role or subroles have"""
  83. role_pks = self.get_descendants(include_self=True).values_list('id', flat=True)
  84. qs = Permission.objects.only('id', 'roles').filter(roles__pk__in=role_pks).distinct()
  85. return qs.defer(None)
  86. def is_belong(self, user_obj):
  87. """whether the ``user_obj`` belongs to this role or superroles"""
  88. return self.users.filter(pk=user_obj.pk).exists()
  89. def add_users(self, *user_or_iterable):
  90. """add users if the users have not belong to this role or subroles
  91. .. Note::
  92. Adding user doesn't add the user who belongs to this role or
  93. all subroles of this role. Adding users directly to ``_users``
  94. is not recommended.
  95. """
  96. if isinstance(user_or_iterable, User):
  97. user_or_iterable = [user_or_iterable]
  98. users_add = []
  99. existing_users = self.users
  100. for user in user_or_iterable:
  101. if not existing_users.filter(pk=user.pk).exists():
  102. users_add.append(user)
  103. if len(users_add) > 0:
  104. self._users.add(*users_add)
  105. def remove_users(self, *user_or_iterable):
  106. """remove users if the users have belong to this role
  107. .. Note::
  108. Removing user doesn't remove the user who have not belong to this
  109. role. All users who belongs to the subroles of this roles are
  110. protected from removing by ``remove_users``.
  111. """
  112. if isinstance(user_or_iterable, User):
  113. user_or_iterable = [user_or_iterable]
  114. users_remove = []
  115. existing_users = self._users
  116. for user in user_or_iterable:
  117. if existing_users.filter(pk=user.pk).exists():
  118. users_remove.append(user)
  119. if len(users_remove) > 0:
  120. self._users.remove(*users_remove)
  121. def add_permissions(self, *perm_or_iterable):
  122. """add permissions if the permissions have not belong to this role or subroles
  123. .. Note::
  124. Adding permissions doesn't add the permission which belongs to this role or
  125. all subroles of this role. Adding permissions directly to ``_permissions``
  126. is not recommended.
  127. """
  128. if isinstance(perm_or_iterable, (basestring, Permission)):
  129. perm_or_iterable = [perm_or_iterable]
  130. existing_perms = self.permissions
  131. for perm in perm_or_iterable:
  132. if isinstance(perm, basestring):
  133. app_label, codename = perm.split('.', 1)
  134. instance = Permission.objects.get(
  135. content_type__app_label=app_label,
  136. codename=codename
  137. )
  138. else:
  139. instance = perm
  140. app_label = perm.content_type.app_label
  141. codename = perm.codename
  142. if not existing_perms.filter(content_type__app_label=app_label, codename=codename).exists():
  143. self._permissions.add(instance)
  144. def remove_permissions(self, *perm_or_iterable):
  145. """remove permissions if the permissions have belong to this role
  146. .. Note::
  147. Removing permission doesn't remove the permission who have not belong to this
  148. role. All permissions who belongs to the subroles of this roles are
  149. protected from removing by ``remove_permissions``.
  150. """
  151. if isinstance(perm_or_iterable, (basestring, Permission)):
  152. perm_or_iterable = [perm_or_iterable]
  153. existing_perms = self.permissions
  154. for perm in perm_or_iterable:
  155. if isinstance(perm, basestring):
  156. app_label, codename = perm.split('.', 1)
  157. instance = Permission.objects.get(
  158. content_type__app_label=app_label,
  159. codename=codename
  160. )
  161. else:
  162. instance = perm
  163. app_label = perm.content_type.app_label
  164. codename = perm.codename
  165. if existing_perms.filter(content_type__app_label=app_label, codename=codename).exists():
  166. self._permissions.remove(instance)