From 6fa1bfec48e5bf6da1ca3c7ce50d2f2ea49b57d8 Mon Sep 17 00:00:00 2001
From: Valentin Deniaud <vdeniaud@entrouvert.com>
Date: Mon, 7 Oct 2019 15:50:21 +0200
Subject: [PATCH 2/2] a2_rbac: update role admins using post_migrate signal
 (#20513)

---
 src/authentic2/a2_rbac/apps.py            |  3 +++
 src/authentic2/a2_rbac/management.py      | 14 ++++++++++++
 src/authentic2/a2_rbac/signal_handlers.py |  6 +++++
 tests/test_a2_rbac.py                     | 28 ++++++++++++++++++++++-
 4 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/src/authentic2/a2_rbac/apps.py b/src/authentic2/a2_rbac/apps.py
index 65cb2f00..10765d16 100644
--- a/src/authentic2/a2_rbac/apps.py
+++ b/src/authentic2/a2_rbac/apps.py
@@ -50,3 +50,6 @@ class Authentic2RBACConfig(AppConfig):
         post_migrate.connect(
             signal_handlers.post_migrate_update_rbac,
             sender=self)
+        post_migrate.connect(
+            signal_handlers.post_migrate_update_role_admins,
+            sender=self)
diff --git a/src/authentic2/a2_rbac/management.py b/src/authentic2/a2_rbac/management.py
index 1a9b249c..8db5e51f 100644
--- a/src/authentic2/a2_rbac/management.py
+++ b/src/authentic2/a2_rbac/management.py
@@ -19,10 +19,12 @@ from django.utils.translation import ugettext_lazy as _, ugettext
 from django.utils.text import slugify
 from django.contrib.contenttypes.models import ContentType
 
+from django_rbac.models import ADMIN_OP
 from django_rbac.utils import get_role_model, get_ou_model
 
 from ..utils import get_fk_model
 from . import utils, app_settings
+from .models import MANAGE_MEMBERS_OP
 
 
 def update_ou_admin_roles(ou):
@@ -141,3 +143,15 @@ def update_content_types_roles():
             ct_admin_role.permissions.add(view_user_perm)
         ct_admin_role.permissions.add(search_ou_perm)
         ct_admin_role.add_child(admin_role)
+
+
+def update_user_admin_roles_permission():
+    roles = get_role_model().objects.filter(slug__startswith='_a2-managers-of-role',
+                                            permissions__operation__slug=ADMIN_OP.slug)
+    for role in roles:
+        old_perm = role.permissions.get(operation__slug=ADMIN_OP.slug)
+        administered_role = old_perm.target
+        admin_role = administered_role.get_admin_role()
+        new_perm = admin_role.permissions.get(operation__slug=MANAGE_MEMBERS_OP.slug)
+        role.permissions.remove(old_perm)
+        role.permissions.add(new_perm)
diff --git a/src/authentic2/a2_rbac/signal_handlers.py b/src/authentic2/a2_rbac/signal_handlers.py
index 0c401296..13a5770d 100644
--- a/src/authentic2/a2_rbac/signal_handlers.py
+++ b/src/authentic2/a2_rbac/signal_handlers.py
@@ -98,3 +98,9 @@ def create_default_permissions(app_config, verbosity=2, interactive=True, using=
         get_operation(ACTIVATE_OP)
         get_operation(CHANGE_EMAIL_OP)
         get_operation(MANAGE_MEMBERS_OP)
+
+
+def post_migrate_update_role_admins(app_config, verbosity=2, interactive=True,
+                             using=DEFAULT_DB_ALIAS, **kwargs):
+    from .management import update_user_admin_roles_permission
+    update_user_admin_roles_permission()
diff --git a/tests/test_a2_rbac.py b/tests/test_a2_rbac.py
index 0e7fd7f1..719043fa 100644
--- a/tests/test_a2_rbac.py
+++ b/tests/test_a2_rbac.py
@@ -28,7 +28,7 @@ from authentic2.models import Service
 from django.core.management import call_command
 
 from authentic2.a2_rbac.models import Role, OrganizationalUnit as OU, RoleAttribute
-from authentic2.a2_rbac.utils import get_default_ou
+from authentic2.a2_rbac.utils import get_default_ou, get_view_user_perm
 from authentic2.a2_rbac.models import (
     Role,
     Permission,
@@ -493,3 +493,29 @@ def test_manager_roles_multi_ou(db, ou1):
 
     # 5 global roles and 4 ou roles for both ous
     assert Role.objects.count() == 5 + 4 + 4
+
+
+def test_update_role_admins_perm(transactional_db, settings, simple_user):
+    from django.core.management.sql import emit_post_migrate_signal
+
+    call_command('flush', verbosity=0, interactive=False,
+                 database='default', reset_sequences=False)
+
+    role = Role.objects.create(name='hop')
+    old_admin_role = Role.objects.get_admin_role(
+            role, ou=role.ou,
+            name='Managers of role "{role}"'.format(
+                role=role),
+            slug='_a2-managers-of-role-{role}'.format(
+                role=role),
+            permissions=(get_view_user_perm(),),
+            self_administered=True,
+            update_name=True,
+            update_slug=True,
+            create=True)
+    simple_user.roles.add(old_admin_role)
+
+    emit_post_migrate_signal(verbosity=0, interactive=False, db='default', created_models=[])
+    assert simple_user.get_all_permissions(role) == \
+        {'a2_rbac.change_role', 'a2_rbac.manage_members_role', 'a2_rbac.search_role',
+         'a2_rbac.view_role'}
-- 
2.20.1

