From b7e6a7ed1e74ec76b051f515acd513b0ad4f9927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Mon, 27 Jul 2020 19:09:18 +0200 Subject: [PATCH] publik: make it possible to create publik menu from pages (#45741) --- combo/apps/publik/views.py | 77 +++++++++++++++++++++++++++++++------- combo/data/models.py | 8 ++-- tests/test_publik.py | 77 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 141 insertions(+), 21 deletions(-) diff --git a/combo/apps/publik/views.py b/combo/apps/publik/views.py index 2855c733..7a0b1613 100644 --- a/combo/apps/publik/views.py +++ b/combo/apps/publik/views.py @@ -17,35 +17,86 @@ import json from django.conf import settings +from django.contrib.auth.decorators import login_required from django.http import Http404, HttpResponse +from combo.data.models import Page + + +def menuitem_url(request, page, subpage=None): + if subpage and subpage.redirect_url: + return subpage.get_redirect_url() + elif subpage: + return request.build_absolute_uri('/'.join(['', page.slug, subpage.slug, ''])) + if page.redirect_url: + return page.get_redirect_url() + return request.build_absolute_uri('/'.join(['', page.slug, ''])) + + +@login_required def services_js(request, *args, **kwargs): if not getattr(settings, 'KNOWN_SERVICES', None): raise Http404() services = [] portal_agent_url = None portal_agent_title = None - for service_id, services_dict in settings.KNOWN_SERVICES.items(): - for service_slug, service in services_dict.items(): - if service.get('secondary') and service_id != 'authentic': + menu_items = [] + + if getattr(settings, 'PUBLIK_EXPLICIT_MENU', False): + pages = Page.objects.filter( + parent_id__isnull=True, + exclude_from_navigation=False) + second_level_pages = Page.objects.filter( + parent__in=pages, + exclude_from_navigation=False) + for page in pages: + if not page.is_visible(request.user, ignore_superuser=True): continue - if service.get('is-portal-agent'): - portal_agent_url = service['url'] - portal_agent_title = service['title'] - services.append({ - 'title': service['title'], - 'slug': service_slug, - 'service_id': service_id, - 'uniq': bool(len([x for x in services_dict.values() if not x.get('secondary')]) == 1), - 'url': service['url'], - 'backoffice_menu_url': service['backoffice-menu-url'], + menu_items.append( + { + 'label': page.title, + 'url': menuitem_url(request, page), + 'slug': page.slug if page.slug != 'index' else 'home', + 'icon': request.build_absolute_uri(page.picture.url) if page.picture else None, }) + for subpage in second_level_pages: + if subpage.parent_id != page.id: + continue + if not subpage.is_visible(request.user, ignore_superuser=True): + continue + menu_items.append( + { + 'label': subpage.title, + 'sub': True, + 'url': menuitem_url(request, page, subpage), + 'slug': subpage.slug, + 'icon': request.build_absolute_uri(subpage.picture.url) if subpage.picture else None, + }) + else: + for service_id, services_dict in settings.KNOWN_SERVICES.items(): + for service_slug, service in services_dict.items(): + if service.get('secondary') and service_id != 'authentic': + continue + if service.get('is-portal-agent'): + portal_agent_url = service['url'] + portal_agent_title = service['title'] + services.append({ + 'title': service['title'], + 'slug': service_slug, + 'service_id': service_id, + 'uniq': bool(len([x for x in services_dict.values() if not x.get('secondary')]) == 1), + 'url': service['url'], + 'backoffice_menu_url': service['backoffice-menu-url'], + }) + response_vars = { 'PUBLIK_ENVIRONMENT_LABEL': settings.TEMPLATE_VARS.get('environment_label'), 'PUBLIK_PORTAL_AGENT_URL': portal_agent_url, 'PUBLIK_PORTAL_AGENT_TITLE': portal_agent_title, 'PUBLIK_PORTAL_AGENT_EXTRA_CSS': settings.TEMPLATE_VARS.get( 'portal_agent_extra_css'), + 'PUBLIK_MENU_ITEMS': menu_items, + 'PUBLIK_EXPLICIT_MENU': getattr(settings, 'PUBLIK_EXPLICIT_MENU', False), 'COMBO_KNOWN_SERVICES': services, } response_body = '\n'.join( diff --git a/combo/data/models.py b/combo/data/models.py index fd808c05..b111c1cd 100644 --- a/combo/data/models.py +++ b/combo/data/models.py @@ -71,14 +71,14 @@ class PostException(Exception): pass -def element_is_visible(element, user=None): +def element_is_visible(element, user=None, ignore_superuser=False): if element.public: if getattr(element, 'restricted_to_unlogged', None) is True: return (user is None or user.is_anonymous) return True if user is None or user.is_anonymous: return False - if user.is_superuser: + if user.is_superuser and not ignore_superuser: return True page_groups = element.groups.all() if not page_groups: @@ -404,8 +404,8 @@ class Page(models.Model): groupnames = ', '.join([x.name for x in groups]) if groups else _('logged users') return _('Private (%s)') % groupnames - def is_visible(self, user=None): - return element_is_visible(self, user=user) + def is_visible(self, user=None, ignore_superuser=False): + return element_is_visible(self, user=user, ignore_superuser=ignore_superuser) def get_cells(self): return CellBase.get_cells(page=self) diff --git a/tests/test_publik.py b/tests/test_publik.py index a187429a..ab563dfd 100644 --- a/tests/test_publik.py +++ b/tests/test_publik.py @@ -1,11 +1,33 @@ +import json +import re + import pytest from webtest import TestApp from django.conf import settings +from django.contrib.auth.models import User, Group + +from combo.data.models import Page + +from . import test_manager pytestmark = pytest.mark.django_db +def login(app): + test_manager.login(app, username='normal-user', password='normal-user') + + +@pytest.fixture +def normal_user(): + try: + user = User.objects.get(username='normal-user') + user.groups = [] + except User.DoesNotExist: + user = User.objects.create_user(username='normal-user', email='', password='normal-user') + return user + + class KnownServices(object): def __init__(self, known_services): self.known_services = known_services @@ -18,18 +40,25 @@ class KnownServices(object): settings.KNOWN_SERVICES = self.orig_value -def test_services_js_no_services(app): +def test_services_js_no_services(app, normal_user): with KnownServices({}): - resp = app.get('/__services.js', status=404) + app.get('/__services.js', status=302) + login(app) + app.get('/__services.js', status=404) -def test_services_js_multiple_wcs(app): + +def test_services_js_multiple_wcs(app, normal_user): + login(app) resp = app.get('/__services.js', status=200) assert resp.content_type == 'text/javascript' assert 'var PUBLIK_ENVIRONMENT_LABEL = null' in resp.text assert 'var PUBLIK_PORTAL_AGENT_URL = null' in resp.text assert '"uniq": false' in resp.text -def test_services_js_portal_agent(app): + +def test_services_js_portal_agent(app, normal_user): + app.get('/__services.js', status=302) # authentication required + login(app) known_services = { 'combo': { 'portal-agent': { @@ -50,3 +79,43 @@ def test_services_js_portal_agent(app): assert resp.content_type == 'text/javascript' assert 'var PUBLIK_PORTAL_AGENT_URL = "http://example.net";' in resp.text assert 'var PUBLIK_PORTAL_AGENT_TITLE = "Portal Agent"' in resp.text + + +def test_services_js_explicit_menu(app, normal_user, settings): + settings.PUBLIK_EXPLICIT_MENU = True + + group1 = Group.objects.create(name='plop1') + group2 = Group.objects.create(name='plop2') + + index_page = Page.objects.create(title='Home', slug='index', + template_name='standard', public=False, + exclude_from_navigation=False) + index_page.groups.set([group1]) + other_page = Page.objects.create(title='Page', slug='page', + template_name='standard', public=False, + exclude_from_navigation=False) + other_page.groups.set([group1]) + sub_page = Page.objects.create(title='Subpage', slug='subpage', + template_name='standard', parent=other_page, public=False, + exclude_from_navigation=False) + sub_page.groups.set([group2]) + last_page = Page.objects.create(title='Last page', slug='lastpage', + template_name='standard', public=False, + exclude_from_navigation=False) + last_page.groups.set([group1]) + + def get_menu_var(resp): + return json.loads(re.findall('var PUBLIK_MENU_ITEMS = (.*);', resp.text)[0]) + + login(app) + resp = app.get('/__services.js', status=200) + assert [x['slug'] for x in get_menu_var(resp)] == [] + + normal_user.groups.set([group1]) + resp = app.get('/__services.js', status=200) + assert [x['slug'] for x in get_menu_var(resp)] == ['home', 'page', 'lastpage'] + assert len(get_menu_var(resp)) == 3 + + normal_user.groups.set([group1, group2]) + resp = app.get('/__services.js', status=200) + assert [x['slug'] for x in get_menu_var(resp)] == ['home', 'page', 'subpage', 'lastpage']