From 375c2f5087bf8803f289e53a3e942977252f254c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 5 Jul 2022 09:31:52 +0200
Subject: [PATCH] data: inject global context in context for cell conditions
 (#66953)

---
 combo/data/models.py  | 15 ++++++++-------
 combo/public/views.py | 27 ++++++++++++++++-----------
 tests/test_public.py  | 22 ++++++++++++++++++----
 3 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/combo/data/models.py b/combo/data/models.py
index fcb7564d..1dc852e9 100644
--- a/combo/data/models.py
+++ b/combo/data/models.py
@@ -1327,21 +1327,22 @@ class CellBase(models.Model, metaclass=CellMeta):
             and validity_info.invalid_datetime <= now()
         )
 
-    def compute_condition(self, request):
+    def compute_condition(self, request, original_context):
         condition = self.condition
         if not condition:
             return True
-        context = self.page.get_extra_variables(request, {})
-        context = RequestContext(request, context)
+        context = RequestContext(request)
+        context.push(original_context)
         try:
             return Template('{%% if %s %%}OK{%% endif %%}' % condition).render(context) == 'OK'
         except (TemplateSyntaxError, VariableDoesNotExist):
             return False
 
-    def is_visible(self, request, check_validity_info=True):
-        condition = self.compute_condition(request=request)
-        if not condition:
-            return False
+    def is_visible(self, request, context=None, check_validity_info=True):
+        if context:
+            condition = self.compute_condition(request=request, original_context=context)
+            if not condition:
+                return False
         if check_validity_info and self.is_hidden_because_invalid():
             return False
         return element_is_visible(self, user=getattr(request, 'user', None))
diff --git a/combo/public/views.py b/combo/public/views.py
index 062f835b..44b400bf 100644
--- a/combo/public/views.py
+++ b/combo/public/views.py
@@ -547,6 +547,15 @@ def publish_page(request, page, status=200, template_name=None):
         if redirect_url:
             return HttpResponseRedirect(redirect_url)
 
+    ctx = {
+        'check_badges': should_check_badges(),
+        'page': page,
+        'pages': pages,
+        'request': request,
+    }
+    ctx.update(getattr(request, 'extra_context_data', {}))
+    modify_global_context(request, ctx)
+
     cells = CellBase.get_cells(
         page=page,
         select_related={'data_linkcell': ['link_page']},
@@ -554,7 +563,7 @@ def publish_page(request, page, status=200, template_name=None):
         cells_exclude=Q(placeholder__in=['_auto_tile', '_dashboard', '_suggested_tile']),
     )
     extend_with_parent_cells(cells, hierarchy=pages)
-    cells = [x for x in cells if x.is_visible(request)]
+    cells = [x for x in cells if x.is_visible(request, context=ctx)]
     mark_duplicated_slugs(cells)
 
     # load assets
@@ -565,16 +574,12 @@ def publish_page(request, page, status=200, template_name=None):
     for cell in cells:
         cell._assets = {a.key: a for a in assets if a.key in cell._asset_keys.keys()}
 
-    ctx = {
-        'check_badges': should_check_badges(),
-        'page': page,
-        'page_cells': cells,
-        'pages': pages,
-        'request': request,
-        'media': sum((cell.media for cell in cells), Media()),
-    }
-    ctx.update(getattr(request, 'extra_context_data', {}))
-    modify_global_context(request, ctx)
+    ctx.update(
+        {
+            'page_cells': cells,
+            'media': sum((cell.media for cell in cells), Media()),
+        }
+    )
     if getattr(settings, 'COMBO_TEST_ALWAYS_RENDER_CELLS_SYNCHRONOUSLY', False):
         ctx['synchronous'] = True
 
diff --git a/tests/test_public.py b/tests/test_public.py
index 8d690593..8b0c515e 100644
--- a/tests/test_public.py
+++ b/tests/test_public.py
@@ -139,9 +139,13 @@ def test_page_contents_group_absence(app, normal_user):
 
 
 def test_page_contents_condition(app, normal_user):
-    page = Page.objects.create(title='Home', slug='index', template_name='standard')
-    TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=0, condition='True')
-    TextCell.objects.create(page=page, placeholder='content', text='Foobaz', order=1, condition='False')
+    page = Page.objects.create(title='Page', slug='page', template_name='standard')
+    cell1 = TextCell.objects.create(
+        page=page, placeholder='content', text='Foobar', order=0, condition='True'
+    )
+    cell2 = TextCell.objects.create(
+        page=page, placeholder='content', text='Foobaz', order=1, condition='False'
+    )
     cell3 = LinkListCell.objects.create(order=1, page=page, placeholder='content')
     LinkCell.objects.create(
         page=page,
@@ -161,12 +165,22 @@ def test_page_contents_condition(app, normal_user):
     )
 
     app = login(app, username='normal-user', password='normal-user')
-    resp = app.get('/', status=200)
+    resp = app.get(page.get_online_url())
     assert 'Foobar' in resp.text
     assert 'Foobaz' not in resp.text
     assert 'Example Site' in resp.text
     assert 'Other Site' not in resp.text
 
+    page.sub_slug = 'foo_id'
+    page.save()
+    cell1.condition = 'foo_id'
+    cell1.save()
+    cell2.condition = 'not foo_id'
+    cell2.save()
+    resp = app.get(page.get_online_url() + '11/')
+    assert 'Foobar' in resp.text
+    assert 'Foobaz' not in resp.text
+
 
 def test_page_footer_acquisition(app):
     Page.objects.all().delete()
-- 
2.35.1

