From 4a2335f039f5b29394b7beb823560a422be07ccb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Wed, 3 Aug 2022 08:09:41 +0200
Subject: [PATCH] backoffice: make roles in inspect page links to authentic
 (#66759)

---
 tests/backoffice_pages/test_form_inspect.py | 33 +++++++++++++++++++++
 wcs/backoffice/management.py                | 14 +++++----
 wcs/roles.py                                | 17 ++++++++++-
 3 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/tests/backoffice_pages/test_form_inspect.py b/tests/backoffice_pages/test_form_inspect.py
index 34543c90d..865b27062 100644
--- a/tests/backoffice_pages/test_form_inspect.py
+++ b/tests/backoffice_pages/test_form_inspect.py
@@ -768,3 +768,36 @@ def test_inspect_page_lazy_list(pub):
     assert 'rendered as an object' in resp.text
     assert resp.pyquery('.test-tool-lazylist-details li:first-child').text() == 'Number of items: 3'
     assert resp.pyquery('.test-tool-lazylist-details li:last-child').text() == 'First items: bar, baz, foo'
+
+
+def test_inspect_page_idp_role(pub):
+    create_user(pub, is_admin=True)
+    FormDef.wipe()
+
+    app = login(get_app(pub))
+
+    role = pub.role_class(name='plop')
+    role.uuid = 'd4b59e1ffb204dfd99fd3760f4952999'
+    role.store()
+
+    formdef = FormDef()
+    formdef.name = 'form title'
+    formdef.fields = []
+    formdef.workflow_roles = {'_receiver': role.id}
+    formdef.store()
+    formdef.data_class().wipe()
+
+    formdata = formdef.data_class()()
+    formdata.just_created()
+    formdata.store()
+
+    pub.cfg['sp'] = {'idp-manage-roles': True}
+    pub.cfg['idp'] = {'xxx': {'metadata_url': 'https://idp.example.net/idp/saml2/metadata'}}
+    pub.write_cfg()
+
+    resp = app.get('%sinspect' % formdata.get_url(backoffice=True), status=200)
+    assert resp.pyquery('[data-function-key="_receiver"] a').text() == 'plop'
+    assert (
+        resp.pyquery('[data-function-key="_receiver"] a').attr.href
+        == 'https://idp.example.net/manage/roles/uuid:d4b59e1ffb204dfd99fd3760f4952999/'
+    )
diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py
index 91d17b7c2..95a766209 100644
--- a/wcs/backoffice/management.py
+++ b/wcs/backoffice/management.py
@@ -3613,7 +3613,7 @@ class FormBackOfficeStatusPage(FormStatusPage):
         if self.formdef.workflow.roles:
             workflow = self.formdef.workflow
             for key, label in (workflow.roles or {}).items():
-                r += htmltext('<li><span class="label">%s</span>') % label
+                r += htmltext('<li data-function-key="%s"><span class="label">%s</span>') % (key, label)
                 r += htmltext('<div class="value">')
                 acting_role_ids = self.filled.get_function_roles(key)
                 acting_role_names = []
@@ -3621,17 +3621,19 @@ class FormBackOfficeStatusPage(FormStatusPage):
                     try:
                         if acting_role_id.startswith('_user:'):
                             acting_role = get_publisher().user_class.get(acting_role_id.split(':')[1])
-                        else:
-                            acting_role = get_publisher().role_class.get(acting_role_id)
-                        if key in (self.filled.workflow_roles or {}):
                             acting_role_names.append(acting_role.name)
                         else:
-                            acting_role_names.append('%s (%s)' % (acting_role.name, _('default')))
+                            acting_role = get_publisher().role_class.get(acting_role_id)
+                            if key not in (self.filled.workflow_roles or {}):
+                                suffix = ' (%s)' % _('default')
+                            else:
+                                suffix = ''
+                            acting_role_names.append(acting_role.get_as_inline_html() + suffix)
                     except KeyError:
                         acting_role_names.append('%s (%s)' % (acting_role_id, _('deleted')))
                 if acting_role_names:
                     acting_role_names.sort()
-                    r += ', '.join(acting_role_names)
+                    r += htmltext(', ').join(acting_role_names)
                 else:
                     r += htmltext('<span class="unset">%s</span>') % _('unset')
                 r += htmltext('</div>')
diff --git a/wcs/roles.py b/wcs/roles.py
index 23251d851..29b346631 100644
--- a/wcs/roles.py
+++ b/wcs/roles.py
@@ -14,12 +14,14 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
+import urllib.parse
 import xml.etree.ElementTree as ET
 
 from django.utils.encoding import force_text
 from quixote import get_publisher
+from quixote.html import htmltext
 
-from .qommon import _, misc
+from .qommon import _, get_cfg, misc
 from .qommon.storage import StorableObject
 
 
@@ -171,6 +173,19 @@ class Role(StorableObject):
                     return role
         return None
 
+    def get_as_inline_html(self):
+        from .qommon.ident.idp import is_idp_managing_user_roles
+
+        if not (is_idp_managing_user_roles() and self.uuid):
+            return self.name
+
+        idps = get_cfg('idp', {})
+        entity_id = list(idps.values())[0]['metadata_url']
+        base_url = entity_id.split('idp/saml2/metadata')[0]
+        url = urllib.parse.urljoin(base_url, '/manage/roles/uuid:%s/' % self.uuid)
+
+        return htmltext('<a href="%(url)s">%(name)s</a>') % {'url': url, 'name': self.name}
+
 
 def logged_users_role():
     volatile_role = Role.volatile()
-- 
2.36.1

