From 6fd0452f26229622fceb0be4a9189d5fe57e4543 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 9 Dec 2021 16:11:53 +0100
Subject: [PATCH] management: add link to form/carddef page in sidebar (#58671)

---
 tests/admin_pages/test_workflow.py      |  1 +
 tests/backoffice_pages/test_all.py      | 18 ++++++++++++++++--
 tests/backoffice_pages/test_carddata.py | 17 ++++++++++++++++-
 wcs/admin/workflows.py                  | 12 ++----------
 wcs/backoffice/data_management.py       |  1 +
 wcs/backoffice/management.py            | 12 ++++++++++++
 wcs/workflows.py                        | 14 ++++++++++++++
 7 files changed, 62 insertions(+), 13 deletions(-)

diff --git a/tests/admin_pages/test_workflow.py b/tests/admin_pages/test_workflow.py
index 95a97087..c0fb2d68 100644
--- a/tests/admin_pages/test_workflow.py
+++ b/tests/admin_pages/test_workflow.py
@@ -3144,6 +3144,7 @@ def test_workflow_category_management_roles(pub, backoffice_user, backoffice_rol
     app.get('/backoffice/workflows/categories/', status=403)
     app.get('/backoffice/workflows/data-sources/', status=403)
     app.get('/backoffice/workflows/mail-templates/', status=403)
+    app.get('/backoffice/workflows/%s/' % workflow.id, status=403)
 
     # no import into other category
     workflow_xml = ET.tostring(workflow.export_to_xml(include_id=True))
diff --git a/tests/backoffice_pages/test_all.py b/tests/backoffice_pages/test_all.py
index 5258b583..2c5aa859 100644
--- a/tests/backoffice_pages/test_all.py
+++ b/tests/backoffice_pages/test_all.py
@@ -331,6 +331,20 @@ def test_backoffice_management_css_class(pub):
     assert resp.pyquery.find('body.section-management')
 
 
+def test_admin_form_page(pub):
+    create_superuser(pub)
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'form title'
+    formdef.fields = []
+    formdef.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/management/form-title/')
+    assert 'backoffice/forms/1/' in resp
+    assert 'backoffice/workflows/_default/' in resp
+
+
 def test_backoffice_listing(pub):
     create_superuser(pub)
     create_environment(pub)
@@ -5374,7 +5388,7 @@ def test_backoffice_create_formdata_backoffice_submission(pub, create_formdata):
     resp = app.get(create_formdata['source_formdef'].get_url(backoffice=True))
 
     # click on first available formdata
-    resp = resp.click(href='%s/' % formdata.id)
+    resp = resp.click('%s-%s' % (create_formdata['source_formdef'].id, formdata.id))
     target_data_class = create_formdata['target_formdef'].data_class()
     assert target_data_class.count() == 0
     # resubmit it through backoffice submission
@@ -5492,7 +5506,7 @@ def test_backoffice_create_formdata_map_fields_by_varname(pub, create_formdata):
     resp = app.get(create_formdata['source_formdef'].get_url(backoffice=True))
 
     # click on first available formdata
-    resp = resp.click(href='%s/' % formdata.id)
+    resp = resp.click('%s-%s' % (create_formdata['source_formdef'].id, formdata.id))
     target_data_class = create_formdata['target_formdef'].data_class()
     assert target_data_class.count() == 0
     # resubmit it through backoffice submission
diff --git a/tests/backoffice_pages/test_carddata.py b/tests/backoffice_pages/test_carddata.py
index 18915573..736bb484 100644
--- a/tests/backoffice_pages/test_carddata.py
+++ b/tests/backoffice_pages/test_carddata.py
@@ -15,7 +15,7 @@ from wcs.wf.wscall import WebserviceCallStatusItem
 from wcs.workflows import ChoiceWorkflowStatusItem, Workflow
 
 from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
-from .test_all import create_user
+from .test_all import create_superuser, create_user
 
 
 def pytest_generate_tests(metafunc):
@@ -47,6 +47,21 @@ def teardown_module(module):
     clean_temporary_pub()
 
 
+def test_admin_card_page(pub):
+    create_superuser(pub)
+    CardDef.wipe()
+    carddef = CardDef()
+    carddef.name = 'foo'
+    carddef.fields = []
+    carddef.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/data/foo/')
+    assert 'backoffice/cards/1/' in resp
+    print(resp)
+    assert 'backoffice/workflows/_carddef_default/' in resp
+
+
 def test_carddata_management(pub):
     CardDef.wipe()
     user = create_user(pub)
diff --git a/wcs/admin/workflows.py b/wcs/admin/workflows.py
index bf384d3f..7b77e68b 100644
--- a/wcs/admin/workflows.py
+++ b/wcs/admin/workflows.py
@@ -2044,16 +2044,8 @@ class WorkflowsDirectory(Directory):
 
     def _q_lookup(self, component):
         directory = WorkflowPage(component)
-        global_access = is_global_accessible()
-        if directory.workflow.id not in ('_default', '_carddef_default') and not global_access:
-            user_roles = set(get_request().user.get_roles())
-            management_roles = set()
-            if directory.workflow.category:
-                management_roles = {
-                    x.id for x in getattr(directory.workflow.category, 'management_roles') or []
-                }
-            if not management_roles.intersection(user_roles):
-                raise errors.AccessForbiddenError()
+        if not directory.workflow.has_user_access():
+            raise errors.AccessForbiddenError()
         return directory
 
     def p_import(self):
diff --git a/wcs/backoffice/data_management.py b/wcs/backoffice/data_management.py
index 868a93b8..7c4da912 100644
--- a/wcs/backoffice/data_management.py
+++ b/wcs/backoffice/data_management.py
@@ -103,6 +103,7 @@ class CardPage(FormPage):
     admin_permission = 'cards'
     formdef_class = CardDef
     search_label = _('Search in card content')
+    formdef_view_label = _('View Card')
 
     @property
     def add(self):
diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py
index 70312dd8..b0470ff2 100644
--- a/wcs/backoffice/management.py
+++ b/wcs/backoffice/management.py
@@ -791,6 +791,7 @@ class FormPage(Directory):
     admin_permission = 'forms'
     formdef_class = FormDef
     search_label = _('Search in form content')
+    formdef_view_label = _('View Form')
     WCS_SYNC_EXPORT_LIMIT = 100  # Arbitrary threshold
 
     def __init__(self, component=None, formdef=None, view=None, update_breadcrumbs=True):
@@ -874,6 +875,17 @@ class FormPage(Directory):
             or self.formdef.category.has_permission('statistics', get_request().user)
         ):
             r += htmltext(' <li class="stats"><a href="stats">%s</a></li>') % _('Statistics')
+
+        if get_publisher().get_backoffice_root().is_global_accessible(self.formdef.backoffice_section):
+            r += htmltext(' <li><a href="%s">%s</a></li>') % (
+                self.formdef.get_admin_url(),
+                self.formdef_view_label,
+            )
+        if self.formdef.workflow.has_user_access():
+            r += htmltext(' <li><a href="%s">%s</a></li>') % (
+                self.formdef.workflow.get_admin_url(),
+                _('View Workflow'),
+            )
         return r.getvalue()
 
     def get_formdata_sidebar(self, qs=''):
diff --git a/wcs/workflows.py b/wcs/workflows.py
index cfa66a31..5a277e79 100644
--- a/wcs/workflows.py
+++ b/wcs/workflows.py
@@ -1103,6 +1103,20 @@ class Workflow(StorableObject):
         criterias = [Contains('slug', slugs)]
         return list(MailTemplate.select(criterias, order_by='name'))
 
+    def has_user_access(self):
+        global_access = get_publisher().get_backoffice_root().is_global_accessible('workflows')
+        if global_access:
+            return True
+        if self.id in ('_default', '_carddef_default'):
+            return True
+        user_roles = set(get_request().user.get_roles())
+        management_roles = set()
+        if self.category:
+            management_roles = {x.id for x in getattr(self.category, 'management_roles') or []}
+        if management_roles.intersection(user_roles):
+            return True
+        return False
+
 
 class XmlSerialisable:
     node_name = None
-- 
2.33.0

