0003-manager-include-roles-along-with-users-in-role-membe.patch
src/authentic2/manager/forms.py | ||
---|---|---|
590 | 590 |
return qs |
591 | 591 | |
592 | 592 | |
593 |
class RoleMembersSearchForm(UserSearchForm): |
|
594 |
all_members = forms.BooleanField(initial=False, label=_('View all members'), required=False) |
|
595 | ||
596 |
def __init__(self, *args, **kwargs): |
|
597 |
disable_all_members = kwargs.pop('disable_all_members', False) |
|
598 |
super().__init__(*args, **kwargs) |
|
599 |
if disable_all_members: |
|
600 |
self.fields['all_members'].widget.attrs['disabled'] = True |
|
601 | ||
602 | ||
593 | 603 |
class UserAddChooseOUForm(OUSearchForm): |
594 | 604 |
ou_permission = 'custom_user.add_user' |
595 | 605 |
src/authentic2/manager/role_views.py | ||
---|---|---|
171 | 171 | |
172 | 172 |
class RoleMembersView(views.HideOUColumnMixin, RoleViewMixin, views.BaseSubTableView): |
173 | 173 |
template_name = 'authentic2/manager/role_members.html' |
174 |
table_class = tables.RoleMembersTable |
|
175 | 174 |
form_class = forms.ChooseUserForm |
176 | 175 |
success_url = '.' |
177 |
search_form_class = forms.UserSearchForm
|
|
176 |
search_form_class = forms.RoleMembersSearchForm
|
|
178 | 177 |
permissions = ['a2_rbac.view_role'] |
179 | 178 | |
179 |
@property |
|
180 |
def table_class(self): |
|
181 |
if self.view_all_members: |
|
182 |
return tables.RoleMembersTable |
|
183 |
return tables.MixedUserRoleTable |
|
184 | ||
180 | 185 |
@property |
181 | 186 |
def title(self): |
182 | 187 |
return self.get_instance_name() |
... | ... | |
189 | 194 |
def can_manage_members(self, value): |
190 | 195 |
self._can_manage_members = value |
191 | 196 | |
197 |
def dispatch(self, request, *args, **kwargs): |
|
198 |
self.children = views.filter_view(self.request, self.get_object().children(include_self=False)) |
|
199 |
return super().dispatch(request, *args, **kwargs) |
|
200 | ||
201 |
def get_table_data(self): |
|
202 |
if self.view_all_members: |
|
203 |
return super().get_table_data() |
|
204 |
members = views.filter_view(self.request, self.object.members.all()) |
|
205 |
members = self.filter_by_search(members) |
|
206 |
return list(self.children) + list(members) |
|
207 | ||
192 | 208 |
def get_table_queryset(self): |
193 |
children = self.object.children(include_self=False) |
|
194 |
via_prefetch = Prefetch('roles', queryset=children, to_attr='via') |
|
209 |
via_prefetch = Prefetch('roles', queryset=self.children, to_attr='via') |
|
195 | 210 |
return self.object.all_members().prefetch_related(via_prefetch) |
196 | 211 | |
212 |
@property |
|
213 |
def view_all_members(self): |
|
214 |
return self.search_form.is_valid() and self.search_form.cleaned_data.get('all_members') |
|
215 | ||
197 | 216 |
def form_valid(self, form): |
198 | 217 |
user = form.cleaned_data['user'] |
199 | 218 |
action = form.cleaned_data['action'] |
... | ... | |
239 | 258 |
kwargs['ou'] = self.object.ou |
240 | 259 |
return kwargs |
241 | 260 | |
261 |
def get_search_form_kwargs(self): |
|
262 |
kwargs = super().get_search_form_kwargs() |
|
263 |
if not self.children: |
|
264 |
kwargs['data']['search-all_members'] = 'on' |
|
265 |
kwargs['disable_all_members'] = True |
|
266 |
return kwargs |
|
267 | ||
242 | 268 |
def get_context_data(self, **kwargs): |
243 | 269 |
ctx = super().get_context_data(**kwargs) |
244 | 270 |
ctx['children'] = list( |
src/authentic2/manager/tables.py | ||
---|---|---|
28 | 28 |
from django_rbac.utils import get_ou_model, get_permission_model, get_role_model |
29 | 29 | |
30 | 30 |
User = get_user_model() |
31 |
Role = get_role_model() |
|
31 | 32 | |
32 | 33 | |
33 | 34 |
class PermissionLinkColumn(tables.LinkColumn): |
... | ... | |
51 | 52 | |
52 | 53 |
class UserLinkColumn(PermissionLinkColumn): |
53 | 54 |
def render(self, **kwargs): |
54 |
user = kwargs['record']
|
|
55 |
record = kwargs['record']
|
|
55 | 56 |
value = super().render(**kwargs) |
56 |
if not user.is_active:
|
|
57 |
if isinstance(record, User) and not record.is_active:
|
|
57 | 58 |
value = html.format_html( |
58 | 59 |
'<span class="disabled">{value} ({disabled})</span>', value=value, disabled=_('disabled') |
59 | 60 |
) |
... | ... | |
91 | 92 |
pass |
92 | 93 | |
93 | 94 | |
95 |
class UserOrRoleColumn(UserLinkColumn): |
|
96 |
def render(self, **kwargs): |
|
97 |
value = super().render(**kwargs) |
|
98 |
if isinstance(kwargs['record'], Role): |
|
99 |
value = html.format_html(_('Members of role {value}'), value=value) |
|
100 |
return value |
|
101 | ||
102 | ||
103 |
class MixedUserRoleTable(tables.Table): |
|
104 |
name = UserOrRoleColumn( |
|
105 |
verbose_name=_('Members'), |
|
106 |
text=lambda x: x.get_full_name() if isinstance(x, User) else x.name, |
|
107 |
orderable=False, |
|
108 |
) |
|
109 | ||
110 |
class Meta: |
|
111 |
attrs = {'class': 'main', 'id': 'user-table'} |
|
112 | ||
113 | ||
94 | 114 |
class RoleTable(tables.Table): |
95 | 115 |
name = tables.LinkColumn( |
96 | 116 |
viewname='a2-manager-role-members', kwargs={'pk': A('pk')}, accessor='name', verbose_name=_('label') |
src/authentic2/manager/templates/authentic2/manager/role_members.html | ||
---|---|---|
62 | 62 |
{% render_table table "authentic2/manager/role_members_table.html" %} |
63 | 63 |
{% endwith %} |
64 | 64 | |
65 |
{% if search_form.cleaned_data.all_members %} |
|
65 | 66 |
{% include "authentic2/manager/export_include.html" with export_view_name="a2-manager-role-members-export" %} |
67 |
{% endif %} |
|
66 | 68 | |
67 | 69 |
{% if view.can_manage_members %} |
68 | 70 |
<form method="post" class="manager-m2m-add-form" id="add-user"> |
src/authentic2/manager/views.py | ||
---|---|---|
164 | 164 |
return self.search_form_class |
165 | 165 | |
166 | 166 |
def get_search_form_kwargs(self): |
167 |
return {'request': self.request, 'data': self.request.GET} |
|
167 |
return {'request': self.request, 'data': self.request.GET.dict()}
|
|
168 | 168 | |
169 | 169 |
def get_search_form(self): |
170 | 170 |
form_class = self.get_search_form_class() |
tests/test_role_manager.py | ||
---|---|---|
119 | 119 |
user2.roles.add(role2) |
120 | 120 | |
121 | 121 |
response = login(app, admin, '/manage/roles/%s/' % role1.id) |
122 |
response.forms['search-form']['search-all_members'] = True |
|
123 |
response = response.forms['search-form'].submit() |
|
122 | 124 |
rows = list( |
123 | 125 |
zip( |
124 | 126 |
[text_content(el) for el in response.pyquery('tr td.username')], |
... | ... | |
375 | 377 |
role = Role.objects.create(name='Role a', ou=get_default_ou()) |
376 | 378 |
getattr(simple_role, 'add_%s' % relation)(role) |
377 | 379 |
resp = app.get(url) |
378 |
assert 'Role a' not in resp.text
|
|
380 |
assert not resp.pyquery('a.role-inheritance-%s:contains("Role a")' % relation)
|
|
379 | 381 |
assert '(view all roles)' in resp.text |
380 | 382 | |
381 | 383 |
resp = resp.click('(view all roles)', href=relation) |
... | ... | |
404 | 406 |
'ou1 - Role 2', |
405 | 407 |
'ou1 - Role 3', |
406 | 408 |
] |
409 | ||
410 | ||
411 |
def test_role_members_user_role_mixed_table(app, superuser, settings, simple_role, simple_user): |
|
412 |
simple_user.roles.add(simple_role) |
|
413 | ||
414 |
url = reverse('a2-manager-role-members', kwargs={'pk': simple_role.pk}) |
|
415 |
resp = login(app, superuser, url) |
|
416 | ||
417 |
# no children, directly display members details |
|
418 |
assert resp.forms['search-form']['search-all_members'].value == 'on' |
|
419 |
assert 'disabled' in resp.forms['search-form']['search-all_members'].attrs |
|
420 |
assert 'Download list as CSV' in resp.text |
|
421 | ||
422 |
column_names = [text_content(el) for el in resp.pyquery('table#user-table th') if text_content(el)] |
|
423 |
assert column_names == [ |
|
424 |
'User', |
|
425 |
'Username', |
|
426 |
'Email Address', |
|
427 |
'First Name', |
|
428 |
'Last Name', |
|
429 |
'Organizational Unit', |
|
430 |
'Direct member', |
|
431 |
'Inherited from', |
|
432 |
] |
|
433 | ||
434 |
rows = [text_content(el) for el in resp.pyquery('tr td.link')] |
|
435 |
assert rows == ['Jôhn Dôe'] |
|
436 | ||
437 |
# add child |
|
438 |
role = Role.objects.create(name='Role a', ou=get_default_ou()) |
|
439 |
user = User.objects.create(username='user1') |
|
440 |
user.roles.add(role) |
|
441 |
simple_role.add_child(role) |
|
442 | ||
443 |
resp = app.get(url) |
|
444 |
assert not resp.forms['search-form']['search-all_members'].value |
|
445 |
assert 'disabled' not in resp.forms['search-form']['search-all_members'].attrs |
|
446 |
assert 'Download list as CSV' not in resp.text |
|
447 | ||
448 |
column_names = [text_content(el) for el in resp.pyquery('table#user-table th') if text_content(el)] |
|
449 |
assert column_names == ['Members'] |
|
450 | ||
451 |
rows = [text_content(el) for el in resp.pyquery('tr td.name')] |
|
452 |
assert rows == ['Members of role Role a', 'Jôhn Dôe'] |
|
453 | ||
454 |
resp.forms['search-form']['search-all_members'] = True |
|
455 |
resp = resp.forms['search-form'].submit() |
|
456 | ||
457 |
assert resp.forms['search-form']['search-all_members'].value == 'on' |
|
458 |
assert 'disabled' not in resp.forms['search-form']['search-all_members'].attrs |
|
459 |
assert 'Download list as CSV' in resp.text |
|
460 | ||
461 |
rows = [text_content(el) for el in resp.pyquery('tr td.link')] |
|
462 |
assert rows == ['user1', 'Jôhn Dôe'] |
|
407 |
- |