from django.db import models from django.utils.translation import gettext_lazy as _, gettext from common.db.models import JMSBaseModel from common.utils import lazyproperty from .permission import Permission from .. import const from ..builtin import BuiltinRole __all__ = ['Role', 'SystemRole', 'OrgRole'] class SystemRoleManager(models.Manager): def get_queryset(self): queryset = super().get_queryset() return queryset.filter(scope=const.Scope.system) class OrgRoleManager(models.Manager): def get_queryset(self): queryset = super().get_queryset() return queryset.filter(scope=const.Scope.org) class Role(JMSBaseModel): """ 定义 角色 | 角色-权限 关系 """ Scope = const.Scope name = models.CharField(max_length=128, verbose_name=_('Name')) scope = models.CharField( max_length=128, choices=Scope.choices, default=Scope.system, verbose_name=_('Scope') ) permissions = models.ManyToManyField( 'rbac.Permission', related_name='roles', blank=True, verbose_name=_('Permissions') ) builtin = models.BooleanField(default=False, verbose_name=_('Builtin')) comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) BuiltinRole = BuiltinRole objects = models.Manager() org_roles = OrgRoleManager() system_roles = SystemRoleManager() class Meta: unique_together = [('name', 'scope')] verbose_name = _('Role') def __str__(self): return '%s(%s)' % (self.name, self.get_scope_display()) def is_system_admin(self): return str(self.id) == self.BuiltinRole.system_admin.id and self.builtin def is_org_admin(self): return str(self.id) == self.BuiltinRole.org_admin.id and self.builtin def is_admin(self): yes = self.is_system_admin() or self.is_org_admin() return yes @staticmethod def get_scope_roles_perms(roles, scope): has_admin = any([r.is_admin() for r in roles]) if has_admin: perms = Permission.objects.all() else: perms = Permission.objects.filter(roles__in=roles).distinct() perms = Permission.clean_permissions(perms, scope=scope) return perms @classmethod def get_roles_permissions(cls, roles): org_roles = [role for role in roles if role.scope == cls.Scope.org] org_perms_id = cls.get_scope_roles_perms(org_roles, cls.Scope.org) \ .values_list('id', flat=True) system_roles = [role for role in roles if role.scope == cls.Scope.system] system_perms_id = cls.get_scope_roles_perms(system_roles, cls.Scope.system) \ .values_list('id', flat=True) perms_id = set(org_perms_id) | set(system_perms_id) permissions = Permission.objects.filter(id__in=perms_id) \ .prefetch_related('content_type') return permissions @classmethod def get_roles_perms(cls, roles): permissions = cls.get_roles_permissions(roles) return Permission.to_perms(permissions) def get_permissions(self): if self.is_admin(): permissions = Permission.objects.all() else: permissions = self.permissions.all() permissions = Permission.clean_permissions(permissions, self.scope) return permissions @lazyproperty def users(self): from .rolebinding import RoleBinding return RoleBinding.get_role_users(self) @lazyproperty def users_amount(self): return self.users.count() @lazyproperty def permissions_amount(self): return self.permissions.count() @classmethod def create_builtin_roles(cls): BuiltinRole.sync_to_db() @property def display_name(self): if not self.builtin: return self.name return gettext(self.name) def is_org(self): return self.scope == const.Scope.org @classmethod def get_roles_by_perm(cls, perm): app_label, codename = perm.split('.') p = Permission.objects.filter( codename=codename, content_type__app_label=app_label ).first() if not p: return p.roles.none() role_ids = list(p.roles.all().values_list('id', flat=True)) admin_ids = [BuiltinRole.system_admin.id, BuiltinRole.org_admin.id] role_ids += admin_ids return cls.objects.filter(id__in=role_ids) class SystemRole(Role): objects = SystemRoleManager() class Meta: proxy = True verbose_name = _('System role') class OrgRole(Role): objects = OrgRoleManager() class Meta: proxy = True verbose_name = _('Organization role')