0006-apply-soft-deletion-logic-when-retrieving-roleparent.patch
src/authentic2/custom_user/models.py | ||
---|---|---|
22 | 22 |
from django.core.exceptions import MultipleObjectsReturned, ValidationError |
23 | 23 |
from django.core.mail import send_mail |
24 | 24 |
from django.db import models, transaction |
25 |
from django.db.models import F |
|
26 |
from django.db.models.query import Q |
|
25 | 27 |
from django.utils import timezone |
26 | 28 |
from django.utils.translation import ugettext_lazy as _ |
27 | 29 | |
... | ... | |
219 | 221 | |
220 | 222 |
def roles_and_parents(self): |
221 | 223 |
qs1 = self.roles.all() |
222 |
qs2 = qs1.model.objects.filter(child_relation__child__in=qs1) |
|
224 |
qs2 = qs1.model.objects.filter( |
|
225 |
Q(child_relation__deleted__isnull=True) |
|
226 |
| Q(child_relation__deleted__lte=F('child_relation__created')), |
|
227 |
child_relation__child__in=qs1, |
|
228 |
) |
|
223 | 229 |
qs = (qs1 | qs2).order_by('name').distinct() |
224 | 230 |
RoleParenting = get_role_parenting_model() |
225 |
rp_qs = RoleParenting.objects.filter(child__in=qs1) |
|
231 |
rp_qs = RoleParenting.objects.filter_out_soft_deleted().filter(child__in=qs1)
|
|
226 | 232 |
qs = qs.prefetch_related(models.Prefetch('child_relation', queryset=rp_qs), 'child_relation__parent') |
227 | 233 |
qs = qs.prefetch_related( |
228 | 234 |
models.Prefetch('members', queryset=self.__class__.objects.filter(pk=self.pk), to_attr='member') |
src/authentic2/management/commands/check-and-repair.py | ||
---|---|---|
23 | 23 |
from django.core.exceptions import ObjectDoesNotExist |
24 | 24 |
from django.core.management.base import BaseCommand |
25 | 25 |
from django.db import connection |
26 |
from django.db.models import Count, Q |
|
26 |
from django.db.models import Count, F, Q
|
|
27 | 27 |
from django.db.models.functions import Lower |
28 | 28 |
from django.db.transaction import atomic |
29 | 29 |
from django.utils.timezone import localtime |
... | ... | |
388 | 388 |
direct_members = manager_role.members.all() |
389 | 389 |
direct_members_count = direct_members.count() |
390 | 390 |
direct_children = Role.objects.filter( |
391 |
parent_relation__parent=manager_role, parent_relation__direct=True |
|
391 |
Q(parent_relation__deleted__isnull=True) |
|
392 |
| Q(parent_relation__deleted__lte=F('parent_relation__created')), |
|
393 |
parent_relation__parent=manager_role, |
|
394 |
parent_relation__direct=True, |
|
392 | 395 |
) |
393 | 396 |
direct_children_count = direct_children.count() |
394 | 397 |
show = members_count or self.verbosity > 1 |
src/authentic2/manager/resources.py | ||
---|---|---|
39 | 39 |
result = set() |
40 | 40 |
for role in instance.roles.all(): |
41 | 41 |
result.add(role) |
42 |
for pr in role.parent_relation.all():
|
|
42 |
for pr in role.parent_relation.filter_out_soft_deleted():
|
|
43 | 43 |
result.add(pr.parent) |
44 | 44 |
return ', '.join(str(x) for x in result) |
45 | 45 |
src/authentic2/manager/role_views.py | ||
---|---|---|
396 | 396 |
) |
397 | 397 |
) |
398 | 398 |
RoleParenting = get_role_parenting_model() |
399 |
rp_qs = RoleParenting.objects.filter(parent__in=children).annotate(name=F('parent__name')) |
|
399 |
rp_qs = ( |
|
400 |
RoleParenting.objects.filter_out_soft_deleted() |
|
401 |
.filter(parent__in=children) |
|
402 |
.annotate(name=F('parent__name')) |
|
403 |
) |
|
400 | 404 |
qs = qs.prefetch_related(Prefetch('parent_relation', queryset=rp_qs, to_attr='via')) |
401 | 405 |
return qs |
402 | 406 | |
... | ... | |
461 | 465 |
) |
462 | 466 |
) |
463 | 467 |
RoleParenting = get_role_parenting_model() |
464 |
rp_qs = RoleParenting.objects.filter(child__in=parents).annotate(name=F('child__name')) |
|
468 |
rp_qs = ( |
|
469 |
RoleParenting.objects.filter_out_soft_deleted() |
|
470 |
.filter(child__in=parents) |
|
471 |
.annotate(name=F('child__name')) |
|
472 |
) |
|
465 | 473 |
qs = qs.prefetch_related(Prefetch('child_relation', queryset=rp_qs, to_attr='via')) |
466 | 474 |
return qs |
467 | 475 |
src/authentic2/manager/tables.py | ||
---|---|---|
182 | 182 |
) |
183 | 183 |
ou = tables.Column() |
184 | 184 |
via = tables.TemplateColumn( |
185 |
'{% if not record.member %}{% for rel in record.child_relation.all %}{{ rel.child }} {% if not'
|
|
185 |
'{% if not record.member %}{% for rel in record.child_relation.filter_out_soft_deleted %}{{ rel.child }} {% if not'
|
|
186 | 186 |
' forloop.last %}, {% endif %}{% endfor %}{% endif %}', |
187 | 187 |
verbose_name=_('Inherited from'), |
188 | 188 |
orderable=False, |
src/authentic2/manager/user_views.py | ||
---|---|---|
643 | 643 |
User = get_user_model() |
644 | 644 |
Role = get_role_model() |
645 | 645 |
RoleParenting = get_role_parenting_model() |
646 |
rp_qs = RoleParenting.objects.filter(child__in=roles) |
|
646 |
rp_qs = RoleParenting.objects.filter_out_soft_deleted().filter(child__in=roles)
|
|
647 | 647 |
qs = Role.objects.all() |
648 | 648 |
qs = qs.prefetch_related(models.Prefetch('child_relation', queryset=rp_qs, to_attr='via')) |
649 | 649 |
qs = qs.prefetch_related( |
src/django_rbac/managers.py | ||
---|---|---|
107 | 107 |
return self.filter(members=user).parents().distinct() |
108 | 108 | |
109 | 109 |
def parents(self, include_self=True, annotate=False): |
110 |
qs = self.model.objects.filter(child_relation__child__in=self) |
|
110 |
qs = self.model.objects.filter( |
|
111 |
Q(child_relation__deleted__isnull=True) |
|
112 |
| Q(child_relation__deleted__lte=F('child_relation__created')), |
|
113 |
child_relation__child__in=self, |
|
114 |
) |
|
111 | 115 |
if include_self: |
112 | 116 |
qs = self | qs |
113 | 117 |
qs = qs.distinct() |
... | ... | |
116 | 120 |
return qs |
117 | 121 | |
118 | 122 |
def children(self, include_self=True, annotate=False): |
119 |
qs = self.model.objects.filter(parent_relation__parent__in=self) |
|
123 |
qs = self.model.objects.filter( |
|
124 |
Q(parent_relation__deleted__isnull=True) |
|
125 |
| Q(parent_relation__deleted__lte=F('child_relation__created')), |
|
126 |
parent_relation__parent__in=self, |
|
127 |
) |
|
120 | 128 |
if include_self: |
121 | 129 |
qs = self | qs |
122 | 130 |
qs = qs.distinct() |
... | ... | |
128 | 136 |
User = get_user_model() |
129 | 137 |
prefetch = Prefetch('roles', queryset=self, to_attr='direct') |
130 | 138 |
return ( |
131 |
User.objects.filter(Q(roles__in=self) | Q(roles__parent_relation__parent__in=self)) |
|
139 |
User.objects.filter( |
|
140 |
Q(roles__in=self) |
|
141 |
| ( |
|
142 |
Q(roles__parent_relation__parent__in=self) |
|
143 |
& ( |
|
144 |
Q(roles__parent_relation__deleted__isnull=True) |
|
145 |
| Q(roles__parent_relation__deleted__lte=F('roles__parent_relation__created')) |
|
146 |
) |
|
147 |
) |
|
148 |
) |
|
132 | 149 |
.distinct() |
133 | 150 |
.prefetch_related(prefetch) |
134 | 151 |
) |
src/django_rbac/models.py | ||
---|---|---|
222 | 222 |
def all_members(self): |
223 | 223 |
User = get_user_model() |
224 | 224 |
prefetch = Prefetch('roles', queryset=self.__class__.objects.filter(pk=self.pk), to_attr='direct') |
225 | ||
226 |
soft_deleted_rps = utils.get_role_parenting_model().objects.filter_out_soft_created() |
|
225 | 227 |
return ( |
226 |
User.objects.filter(Q(roles=self) | Q(roles__parent_relation__parent=self)) |
|
228 |
User.objects.filter( |
|
229 |
Q(roles=self) |
|
230 |
| Q(roles__parent_relation__parent=self) & ~Q(roles__parent_relation__in=soft_deleted_rps) |
|
231 |
) |
|
227 | 232 |
.distinct() |
228 | 233 |
.prefetch_related(prefetch) |
229 | 234 |
) |
tests_rbac/test_rbac.py | ||
---|---|---|
66 | 66 |
assert role.parents().count() == i + 1 |
67 | 67 |
assert role.children(False).count() == 6 - i - 1 |
68 | 68 |
assert role.parents(False).count() == i |
69 |
RoleParenting.objects.filter(parent=roles[2], child=roles[3], direct=True).delete() |
|
70 |
assert RoleParenting.objects.filter(direct=True).count() == 4 |
|
71 |
assert RoleParenting.objects.filter(direct=False).count() == 2 |
|
69 |
for rp in RoleParenting.objects.filter(parent=roles[2], child=roles[3], direct=True): |
|
70 |
rp.soft_delete() |
|
71 |
assert ( |
|
72 |
RoleParenting.objects.filter_out_soft_deleted() |
|
73 |
.filter( |
|
74 |
direct=True, |
|
75 |
) |
|
76 |
.count() |
|
77 |
== 4 |
|
78 |
) |
|
79 |
assert ( |
|
80 |
RoleParenting.objects.filter_out_soft_deleted() |
|
81 |
.filter( |
|
82 |
direct=False, |
|
83 |
) |
|
84 |
.count() |
|
85 |
== 2 |
|
86 |
) |
|
72 | 87 |
# test that it works with cycles |
73 | 88 |
RoleParenting.objects.create(parent=roles[2], child=roles[3]) |
74 | 89 |
RoleParenting.objects.create(parent=roles[5], child=roles[0]) |
... | ... | |
77 | 92 |
assert role.parents().count() == 6 |
78 | 93 | |
79 | 94 | |
95 |
def test_role_parenting_soft_delete_children(db): |
|
96 |
OrganizationalUnit = utils.get_ou_model() |
|
97 |
Role = utils.get_role_model() |
|
98 |
RoleParenting = utils.get_role_parenting_model() |
|
99 | ||
100 |
ou = OrganizationalUnit.objects.create(name='ou') |
|
101 |
roles = [] |
|
102 |
for i in range(10): |
|
103 |
roles.append(Role.objects.create(name='r%d' % i, ou=ou)) |
|
104 |
assert not len(RoleParenting.objects.all()) |
|
105 | ||
106 |
rps = [] |
|
107 |
for i in range(5): |
|
108 |
rps.append(RoleParenting.objects.create(parent=roles[9 - i], child=roles[i])) |
|
109 |
assert len(RoleParenting.objects.all()) == 5 |
|
110 |
for i in range(5): |
|
111 |
roles[9 - i].remove_child(roles[i]) |
|
112 |
assert len(RoleParenting.objects.all()) == 5 |
|
113 |
assert len(RoleParenting.objects.filter_out_soft_deleted()) == 4 - i |
|
114 |
for i in range(5): |
|
115 |
roles[9 - i].add_child(roles[i]) |
|
116 |
assert len(RoleParenting.objects.all()) == 5 |
|
117 |
assert len(RoleParenting.objects.filter_out_soft_deleted()) == i + 1 |
|
118 | ||
119 | ||
120 |
def test_role_parenting_soft_delete_parents(db): |
|
121 |
OrganizationalUnit = utils.get_ou_model() |
|
122 |
Role = utils.get_role_model() |
|
123 |
RoleParenting = utils.get_role_parenting_model() |
|
124 | ||
125 |
ou = OrganizationalUnit.objects.create(name='ou') |
|
126 |
roles = [] |
|
127 |
for i in range(10): |
|
128 |
roles.append(Role.objects.create(name='r%d' % i, ou=ou)) |
|
129 |
assert not len(RoleParenting.objects.all()) |
|
130 | ||
131 |
rps = [] |
|
132 |
for i in range(5): |
|
133 |
rps.append(RoleParenting.objects.create(child=roles[9 - i], parent=roles[i])) |
|
134 |
assert len(RoleParenting.objects.all()) == 5 |
|
135 |
for i in range(5): |
|
136 |
roles[9 - i].remove_parent(roles[i]) |
|
137 |
assert len(RoleParenting.objects.all()) == 5 |
|
138 |
assert len(RoleParenting.objects.filter_out_soft_deleted()) == 4 - i |
|
139 |
for i in range(5): |
|
140 |
roles[9 - i].add_parent(roles[i]) |
|
141 |
assert len(RoleParenting.objects.all()) == 5 |
|
142 |
assert len(RoleParenting.objects.filter_out_soft_deleted()) == i + 1 |
|
143 | ||
144 | ||
80 | 145 |
SIZE = 1000 |
81 | 146 |
SPAN = 50 |
82 | 147 | |
83 |
- |