From 250e11a1a8473ca04a4a201f60c20978b4d3f6f5 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Mon, 11 Oct 2021 14:53:15 +0200 Subject: [PATCH 1/2] public: move page resolve code to utils (#57672) --- combo/data/utils.py | 59 ++++++++++++++++++++++++++++++++++++++++++- combo/public/views.py | 56 ++++++---------------------------------- 2 files changed, 66 insertions(+), 49 deletions(-) diff --git a/combo/data/utils.py b/combo/data/utils.py index 0780c985..590b36ad 100644 --- a/combo/data/utils.py +++ b/combo/data/utils.py @@ -27,7 +27,11 @@ from django.utils.translation import ugettext_lazy as _ from combo.apps.assets.models import Asset from combo.apps.assets.utils import add_tar_content, clean_assets_files, tar_assets_files, untar_assets_files -from .models import Page +from .models import Page, extract_context_from_sub_slug + + +class MissingSubSlug(Exception): + pass class ImportSiteError(Exception): @@ -196,3 +200,56 @@ def import_site_tar(fd, if_empty=False, clean=False, overwrite=False, request=No data.update(untar_assets_files(tar, overwrite=overwrite)) pages = import_site(data, if_empty=if_empty, clean=clean, request=request) return pages + + +def get_page_from_url_parts(parts, request=None): + pages = {} + for page in Page.objects.filter(slug__in=parts): + if not page.slug in pages: + pages[page.slug] = [] + pages[page.slug].append(page) + + if not pages: + return + + i = 0 + hierarchy_ids = [None] + while i < len(parts): + slug_pages = pages.get(parts[i]) + if slug_pages is None or len(slug_pages) == 0: + page = None + break + if len(slug_pages) == 1: + page = slug_pages[0] + else: + # multiple pages with same slugs + try: + page = [x for x in slug_pages if x.parent_id == hierarchy_ids[-1]][0] + except IndexError: + page = None + break + if page.parent_id != hierarchy_ids[-1]: + if i == 0: + # root page should be at root but maybe the page is a child of + # /index/, and as /index/ is silent the page would appear + # directly under /; this is not a suggested practice. + if page.parent.slug != 'index' and page.parent.parent_id is not None: + page = None + break + else: + page = None + break + if page.sub_slug: + if parts[i + 1 :] == []: + raise MissingSubSlug + extra = extract_context_from_sub_slug(page.sub_slug, parts[i + 1]) + if extra is None: + page = None + break + if request: + request.extra_context_data.update(extra) + parts = parts[: i + 1] + parts[i + 2 :] # skip variable component + i += 1 + hierarchy_ids.append(page.id) + + return page diff --git a/combo/public/views.py b/combo/public/views.py index 0cd93d60..8e581e42 100644 --- a/combo/public/views.py +++ b/combo/public/views.py @@ -55,8 +55,8 @@ from combo.data.models import ( PostException, Redirect, TextCell, - extract_context_from_sub_slug, ) +from combo.data.utils import MissingSubSlug, get_page_from_url_parts from combo.profile.models import Profile from combo.profile.utils import get_user_from_name_id @@ -481,56 +481,16 @@ def page(request): request.session['visited'] = True return HttpResponseRedirect(settings.COMBO_WELCOME_PAGE_PATH) - pages = {} - for page in Page.objects.filter(slug__in=parts): - if not page.slug in pages: - pages[page.slug] = [] - pages[page.slug].append(page) + try: + page = get_page_from_url_parts(parts, request) + except MissingSubSlug: + # a sub slug is expected but was not found; redirect to parent + # page as a mitigation. + return HttpResponseRedirect('..') - if pages == {} and parts == ['index'] and Page.objects.count() == 0: + if page is None and parts == ['index'] and Page.objects.count() == 0: return empty_site(request) - i = 0 - hierarchy_ids = [None] - while i < len(parts): - slug_pages = pages.get(parts[i]) - if slug_pages is None or len(slug_pages) == 0: - page = None - break - if len(slug_pages) == 1: - page = slug_pages[0] - else: - # multiple pages with same slugs - try: - page = [x for x in slug_pages if x.parent_id == hierarchy_ids[-1]][0] - except IndexError: - page = None - break - if page.parent_id != hierarchy_ids[-1]: - if i == 0: - # root page should be at root but maybe the page is a child of - # /index/, and as /index/ is silent the page would appear - # directly under /; this is not a suggested practice. - if page.parent.slug != 'index' and page.parent.parent_id is not None: - page = None - break - else: - page = None - break - if page.sub_slug: - if parts[i + 1 :] == []: - # a sub slug is expected but was not found; redirect to parent - # page as a mitigation. - return HttpResponseRedirect('..') - extra = extract_context_from_sub_slug(page.sub_slug, parts[i + 1]) - if extra is None: - page = None - break - request.extra_context_data.update(extra) - parts = parts[: i + 1] + parts[i + 2 :] # skip variable component - i += 1 - hierarchy_ids.append(page.id) - if not url.endswith('/') and settings.APPEND_SLASH: # this is useful to allow /login, /manage, and other non-page URLs to # work. re.sub is used to replace repeated slashes by single ones, -- 2.30.2