def form_valid(self, form): RoleParenting = get_role_parenting_model() role = form.cleaned_data['role'] action = form.cleaned_data['action'] if self.can_change: if action == 'add': if RoleParenting.objects.filter(parent=self.object, child=role, direct=True).exists(): messages.warning( self.request, _('Role "%s" is already a ' 'child of this role.') % role.name) else: self.object.add_child(role) hooks.call_hooks('event', name='manager-add-child-role', user=self.request.user, parent=self.object, child=role) elif action == 'remove': hooks.call_hooks('event', name='manager-remove-child-role', user=self.request.user, parent=self.object, child=role) self.object.remove_child(role) else: messages.warning(self.request, _('You are not authorized')) return super(RoleChildrenView, self).form_valid(form)
def roles_and_parents(self): qs1 = self.roles.all() qs2 = qs1.model.objects.filter(child_relation__child=qs1) qs = (qs1 | qs2).order_by('name').distinct() RoleParenting = get_role_parenting_model() rp_qs = RoleParenting.objects.filter(child=qs1) qs = qs.prefetch_related(models.Prefetch( 'child_relation', queryset=rp_qs), 'child_relation__parent') qs = qs.prefetch_related(models.Prefetch( 'members', queryset=self.__class__.objects.filter(pk=self.pk), to_attr='member')) return qs
def test_role_parenting(db): OrganizationalUnit = utils.get_ou_model() Role = utils.get_role_model() RoleParenting = utils.get_role_parenting_model() ou = OrganizationalUnit.objects.create(name='ou') roles = [] for i in range(10): roles.append(Role.objects.create(name='r%d' % i, ou=ou)) assert Role.objects.count() == 10 assert RoleParenting.objects.count() == 0 for i in range(1, 3): RoleParenting.objects.create(parent=roles[i - 1], child=roles[i]) assert RoleParenting.objects.filter(direct=True).count() == 2 assert RoleParenting.objects.filter(direct=False).count() == 1 for i, role in enumerate(roles[:3]): assert role.children().count() == 3 - i assert role.parents().count() == i + 1 assert role.children(False).count() == 3 - i - 1 assert role.parents(False).count() == i for i in range(4, 6): RoleParenting.objects.create(parent=roles[i - 1], child=roles[i]) assert RoleParenting.objects.filter(direct=True).count() == 4 assert RoleParenting.objects.filter(direct=False).count() == 2 for i, role in enumerate(roles[3:6]): assert role.children().count() == 3 - i assert role.parents().count() == i + 1 assert role.children(False).count() == 3 - i - 1 assert role.parents(False).count() == i RoleParenting.objects.create(parent=roles[2], child=roles[3]) assert RoleParenting.objects.filter(direct=True).count() == 5 assert RoleParenting.objects.filter(direct=False).count() == 10 for i in range(6): assert roles[i].parents().distinct().count() == i + 1 for i, role in enumerate(roles[:6]): assert role.children().count() == 6 - i assert role.parents().count() == i + 1 assert role.children(False).count() == 6 - i - 1 assert role.parents(False).count() == i RoleParenting.objects.filter(parent=roles[2], child=roles[3], direct=True).delete() assert RoleParenting.objects.filter(direct=True).count() == 4 assert RoleParenting.objects.filter(direct=False).count() == 2 # test that it works with cycles RoleParenting.objects.create(parent=roles[2], child=roles[3]) RoleParenting.objects.create(parent=roles[5], child=roles[0]) for role in roles[:6]: assert role.children().count() == 6 assert role.parents().count() == 6
def roles_and_parents(self): qs1 = self.roles.all() qs2 = qs1.model.objects.filter(child_relation__child__in=qs1) qs = (qs1 | qs2).order_by('name').distinct() RoleParenting = get_role_parenting_model() rp_qs = RoleParenting.objects.filter(child__in=qs1) qs = qs.prefetch_related( models.Prefetch('child_relation', queryset=rp_qs), 'child_relation__parent') qs = qs.prefetch_related( models.Prefetch('members', queryset=self.__class__.objects.filter(pk=self.pk), to_attr='member')) return qs
def form_valid(self, form): RoleParenting = get_role_parenting_model() role = form.cleaned_data["role"] action = form.cleaned_data["action"] if self.can_change: if action == "add": if RoleParenting.objects.filter(parent=self.object, child=role, direct=True).exists(): messages.warning(self.request, _('Role "%s" is already a ' "child of this role.") % role.name) else: self.object.add_child(role) elif action == "remove": self.object.remove_child(role) else: messages.warning(self.request, _("You are not authorized")) return super(RoleChildrenView, self).form_valid(form)
def get_table_queryset(self): if self.is_ou_specified(): roles = self.object.roles.all() User = get_user_model() Role = get_role_model() RoleParenting = get_role_parenting_model() rp_qs = RoleParenting.objects.filter(child=roles) qs = Role.objects.all() qs = qs.prefetch_related(models.Prefetch( 'child_relation', queryset=rp_qs, to_attr='via')) qs = qs.prefetch_related(models.Prefetch( 'members', queryset=User.objects.filter(pk=self.object.pk), to_attr='member')) qs2 = self.request.user.filter_by_perm('a2_rbac.change_role', qs) managable_ids = map(str, qs2.values_list('pk', flat=True)) qs = qs.extra(select={'has_perm': 'a2_rbac_role.id in (%s)' % ', '.join(managable_ids)}) return qs else: return self.object.roles_and_parents()
def test_massive_role_parenting(db): User = get_user_model() Role = utils.get_role_model() RoleParenting = utils.get_role_parenting_model() Permission = utils.get_permission_model() user = User.objects.create(username='******') roles = [] # Try a depth=10 tree of roles for i in range(0, SIZE): name = 'role%s' % i roles.append(Role(pk=i + 1, name=name, slug=name)) Role.objects.bulk_create(roles) relations = [] for i in range(0, SIZE): if not i: continue relations.append( RoleParenting(parent=roles[i], child=roles[(i - 1) / SPAN])) RoleParenting.objects.bulk_create(relations) RoleParenting.objects.update_transitive_closure() operation, created = models.Operation.objects.get_or_create( slug='admin', defaults={'name': 'Administration'}) perm, created = Permission.objects.get_or_create( operation=operation, target_ct=ContentType.objects.get_for_model(ContentType), target_id=ContentType.objects.get_for_model(User).id) roles[0].members.add(user) Role.objects.get(pk=roles[-1].pk).permissions.add(perm) b = time.time() for i in range(1000): assert models.Operation.objects.has_perm(user, 'admin', User) t = time.time() - b assert float(t) / 1000 < 0.008 b = time.time() for i in range(1000): assert (list(Role.objects.for_user(user).order_by('pk')) == list( Role.objects.order_by('pk'))) t = time.time() - b assert float(t) / 1000 < 0.1 b = time.time()
def parentings(self): """ Update parentings (delete everything then create) """ created, deleted = [], [] Parenting = get_role_parenting_model() for parenting in Parenting.objects.filter(child=self._obj, direct=True): parenting.delete() deleted.append(parenting) if self._parents: for parent_d in self._parents: parent = search_role(parent_d) if not parent: raise DataImportError("Could not find role : %s" % parent_d) created.append( Parenting.objects.create(child=self._obj, direct=True, parent=parent)) return created, deleted
def export_json(self, attributes=False, parents=False, permissions=False): d = { 'uuid': self.uuid, 'slug': self.slug, 'name': self.name, 'description': self.description, 'external_id': self.external_id, 'ou': self.ou and self.ou.natural_key_json(), 'service': self.service and self.service.natural_key_json() } if attributes: for attribute in self.attributes.all(): d.setdefault('attributes', []).append(attribute.to_json()) if parents: RoleParenting = rbac_utils.get_role_parenting_model() for parenting in RoleParenting.objects.filter(child_id=self.id, direct=True): d.setdefault('parents', []).append(parenting.parent.natural_key_json()) if permissions: for perm in self.permissions.all(): d.setdefault('permissions', []).append(perm.export_json()) return d