From a34c0e385a2b7c2a62290da4a125d7055e49c7c0 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Tue, 22 Sep 2020 13:51:08 +0200
Subject: [PATCH] manager: allow role slug edition (#46656)

---
 src/authentic2/manager/forms.py      |  2 +-
 src/authentic2/manager/role_views.py |  6 +++++-
 src/authentic2/manager/tables.py     |  2 +-
 tests/test_manager.py                | 13 +++++++++++++
 4 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/authentic2/manager/forms.py b/src/authentic2/manager/forms.py
index 475e0607..c7d86aab 100644
--- a/src/authentic2/manager/forms.py
+++ b/src/authentic2/manager/forms.py
@@ -610,17 +610,17 @@ class NameSearchForm(CssClass, PrefixFormMixin, FormWithRequest):
 
 class RoleEditForm(SlugMixin, HideOUFieldMixin, LimitQuerysetFormMixin, CssClass,
                    forms.ModelForm):
     ou = forms.ModelChoiceField(queryset=get_ou_model().objects,
                                 required=True, label=_('Organizational unit'))
 
     class Meta:
         model = get_role_model()
-        fields = ('name', 'ou', 'description')
+        fields = ('name', 'slug', 'ou', 'description')
 
 
 class OUEditForm(SlugMixin, CssClass, forms.ModelForm):
     def __init__(self, *args, **kwargs):
         super(OUEditForm, self).__init__(*args, **kwargs)
         self.fields['name'].label = _('label').title()
 
     class Meta:
diff --git a/src/authentic2/manager/role_views.py b/src/authentic2/manager/role_views.py
index d7a54c5a..fed5957d 100644
--- a/src/authentic2/manager/role_views.py
+++ b/src/authentic2/manager/role_views.py
@@ -25,16 +25,17 @@ from django.contrib import messages
 from django.contrib.contenttypes.models import ContentType
 from django.db import transaction
 from django.db.models.query import Q, Prefetch
 from django.db.models import Count, F
 from django.contrib.auth import get_user_model
 
 from django_rbac.utils import get_role_model, get_permission_model, get_ou_model
 
+from authentic2.forms.profile import modelform_factory
 from authentic2.utils import redirect
 from authentic2 import hooks, data_transfer
 
 from . import tables, views, resources, forms, app_settings
 from .utils import has_show_username
 
 
 class RolesMixin(object):
@@ -81,19 +82,22 @@ class RolesView(views.HideOUColumnMixin, RolesMixin, views.BaseTableView):
 listing = RolesView.as_view()
 
 
 class RoleAddView(views.BaseAddView):
     template_name = 'authentic2/manager/role_add.html'
     model = get_role_model()
     title = _('Add role')
     success_view_name = 'a2-manager-role-members'
+    exclude_fields = ('slug',)
 
     def get_form_class(self):
-        return forms.get_role_form_class()
+        form = forms.get_role_form_class()
+        fields = [x for x in form.base_fields.keys() if x not in self.exclude_fields]
+        return modelform_factory(self.model, form=form, fields=fields)
 
     def form_valid(self, form):
         response = super(RoleAddView, self).form_valid(form)
         hooks.call_hooks('event', name='manager-add-role', user=self.request.user,
                          instance=form.instance, form=form)
         return response
 
 
diff --git a/src/authentic2/manager/tables.py b/src/authentic2/manager/tables.py
index 5175b6b7..1368e6e4 100644
--- a/src/authentic2/manager/tables.py
+++ b/src/authentic2/manager/tables.py
@@ -110,17 +110,17 @@ class RoleTable(tables.Table):
                              accessor='name', verbose_name=_('label'))
     ou = tables.Column()
     member_count = tables.Column(verbose_name=_('Direct member count'),
                                  orderable=False)
 
     class Meta:
         model = get_role_model()
         attrs = {'class': 'main', 'id': 'role-table'}
-        fields = ('name', 'ou', 'member_count')
+        fields = ('name', 'slug', 'ou', 'member_count')
 
 
 class PermissionTable(tables.Table):
     operation = tables.Column()
     scope = tables.Column()
     target = tables.Column()
 
     class Meta:
diff --git a/tests/test_manager.py b/tests/test_manager.py
index 317c434d..3160f8f6 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -79,16 +79,17 @@ def test_manager_create_ou(superuser_or_admin, app):
 def test_manager_create_role(superuser_or_admin, app):
     non_admin_roles = Role.objects.exclude(slug__startswith='_')
 
     ou_add = login(app, superuser_or_admin, reverse('a2-manager-role-add'))
     form = ou_add.form
     assert 'name' in form.fields
     assert 'description' in form.fields
     assert 'ou' not in form.fields
+    assert 'slug' not in form.fields
     form.set('name', 'New role')
     response = form.submit().follow()
     assert non_admin_roles.count() == 1
     role = non_admin_roles.get()
     assert response.request.path == reverse('a2-manager-role-members', kwargs={'pk': role.pk})
     role_list = app.get(reverse('a2-manager-roles'))
     assert 'New role' in role_list
 
@@ -110,16 +111,27 @@ def test_manager_create_role(superuser_or_admin, app):
     assert 'description' in form.fields
     assert 'ou' in form.fields
     options = [o[2] for o in form.fields['ou'][0].options]
     assert len(options) == 3
     assert '---------' in options
     assert 'New OU' in options
 
 
+def test_manager_edit_role_slug(superuser_or_admin, app, simple_role):
+    assert Role.objects.get(name='simple role').slug == 'simple-role'
+    resp = login(app, superuser_or_admin,
+                 reverse('a2-manager-role-edit', kwargs={'pk': simple_role.pk}))
+    form = resp.form
+    assert 'slug' in form.fields
+    form.set('slug', 'new-simple-role-slug')
+    form.submit().follow()
+    assert Role.objects.get(name='simple role').slug == 'new-simple-role-slug'
+
+
 def test_manager_user_password_reset(app, superuser, simple_user):
     resp = login(app, superuser,
                  reverse('a2-manager-user-detail', kwargs={'pk': simple_user.pk}))
     assert len(mail.outbox) == 0
     resp = resp.forms['object-actions'].submit('password_reset')
     assert 'A mail was sent to' in resp
     assert len(mail.outbox) == 1
     url = get_link_from_mail(mail.outbox[0])
@@ -361,16 +373,17 @@ def test_manager_one_ou(app, superuser, admin, simple_role, settings):
         # admin enroled only in the Manager role, other roles are inherited
         assert len(q('table tbody tr td.via')) == 6
         assert len(q('table tbody tr td.via:empty')) == 2
         for elt in q('table tbody td.name a'):
             assert 'Manager' in elt.text or elt.text == 'simple role'
 
         # test role listing
         response = app.get('/manage/roles/')
+        assert [x.text for x in response.pyquery('td.slug')] == ['simple-role']
         assert 'search-ou' not in response.form.fields
         q = response.pyquery.remove_namespaces()
         assert len(q('table tbody tr')) == 1
         assert q('table tbody td.name').text() == u'simple role'
 
         response.form.set('search-internals', True)
         response = response.form.submit()
         q = response.pyquery.remove_namespaces()
-- 
2.28.0

