from django.apps import apps from django.contrib.auth.models import ContentType as DjangoContentType from django.contrib.auth.models import Permission as DjangoPermission from django.db.models import Q from django.utils.translation import gettext_lazy as _ from common.utils import lazyproperty from .. import const Scope = const.Scope __all__ = ['Permission', 'ContentType'] class ContentType(DjangoContentType): class Meta: proxy = True verbose_name = _('ContentType') _apps_map = {} @property def app_model(self): return '%s.%s' % (self.app_label, self.model) @classmethod def apps_map(cls): from ..tree import app_nodes_data if cls._apps_map: return cls._apps_map mapper = {} for d in app_nodes_data: i = d['id'] name = d.get('name') if not name: config = apps.get_app_config(d['id']) if config: name = config.verbose_name if name: mapper[i] = name cls._apps_map = mapper return mapper @property def app_display(self): return self.apps_map().get(self.app_label) @lazyproperty def fields(self): model = self.model_class() return model._meta.fields @lazyproperty def field_names(self): return [f.name for f in self.fields] @lazyproperty def filter_field_names(self): names = [] if 'name' in self.field_names: names.append('name') if 'address' in self.field_names: names.append('address') return names def filter_queryset(self, queryset, keyword): q = Q() for name in self.filter_field_names: q |= Q(**{name + '__icontains': keyword}) return queryset.filter(q) class Permission(DjangoPermission): """ 权限类 """ class Meta: proxy = True verbose_name = _('Permissions') @classmethod def to_perms(cls, queryset): perms = queryset.values_list( 'content_type__app_label', 'codename' ) perms = list(set(["%s.%s" % (ct, codename) for ct, codename in perms])) return sorted(perms) @property def app_label_codename(self): return '%s.%s' % (self.content_type.app_label, self.codename) @classmethod def get_define_permissions_q(cls, defines): """ :param defines: [(app, model, codename),] :return: """ if not defines: return None q = Q() for define in defines: app_label, model, actions, resource, *args = list(define) kwargs = {} if app_label != '*': kwargs['content_type__app_label'] = app_label if model != '*': kwargs['content_type__model'] = model actions_list = [a.strip() for a in actions.split(',')] actions_regex = '|'.join(actions_list) if actions == '*' and resource == '*': pass elif actions == '*' and resource != '*': kwargs['codename__iregex'] = r'[a-z]+_{}$'.format(resource) elif actions != '*' and resource == '*': kwargs['codename__iregex'] = r'({})_[a-z]+'.format(actions_regex) else: kwargs['codename__iregex'] = r'({})_{}$'.format(actions_regex, resource) q |= Q(**kwargs) return q @classmethod def clean_permissions(cls, permissions, scope=Scope.system): if scope == Scope.org: excludes = const.org_exclude_permissions else: excludes = const.system_exclude_permissions q = cls.get_define_permissions_q(excludes) if q: permissions = permissions.exclude(q) return permissions @staticmethod def create_tree_nodes(permissions, scope, check_disabled=False): from ..tree import PermissionTreeUtil util = PermissionTreeUtil(permissions, scope, check_disabled) return util.create_tree_nodes() @classmethod def get_permissions(cls, scope): permissions = cls.objects.all() permissions = cls.clean_permissions(permissions, scope=scope) return permissions