def test_population_and_value_getting(root_page, django_assert_num_queries):
    domestic_homepage = HomePageFactory(parent=root_page)
    topic_page = TopicLandingPageFactory(parent=domestic_homepage,
                                         slug='topic')
    article_list_page = ArticleListingPageFactory(parent=topic_page,
                                                  slug='list')
    article_page = ArticlePageFactory(parent=article_list_page, slug='article')

    Site.objects.all().delete()
    site = Site.objects.create(
        site_name='Great Domestic',
        hostname='domestic.trade.great',
        root_page=domestic_homepage,
    )

    # Trigger population of site root paths cache
    Site.get_site_root_paths()

    # Prefetch content type for this page
    root_page.specific_class

    # With the two potential queries above out of the way,
    # population should only use as single datatbase query
    with django_assert_num_queries(1):
        result = PageIDCache.populate()

    # Check result looks as expected
    assert result == {
        'by-path': {
            f'{site.id}:/': domestic_homepage.id,
            f'{site.id}:/topic/': topic_page.id,
            f'{site.id}:/topic/list/': article_list_page.id,
            f'{site.id}:/topic/list/article/': article_page.id
        },
        'by-slug': {
            'EXPORT_READINESS:great-domestic-home': domestic_homepage.id,
            'EXPORT_READINESS:topic': topic_page.id,
            'EXPORT_READINESS:list': article_list_page.id,
            'EXPORT_READINESS:article': article_page.id,
        },
    }

    # Check get_for_path()
    result_1 = PageIDCache.get_for_path('/', site.id)
    assert result_1 == domestic_homepage.id
    result_2 = PageIDCache.get_for_path('/topic/list/article/', site.id)
    assert result_2 == article_page.id

    # Check invalid get_for_path()
    assert PageIDCache.get_for_path('123', 99) is None

    # Check get_for_slug()
    result_1 = PageIDCache.get_for_slug('topic', 'EXPORT_READINESS')
    assert result_1 == topic_page.id
    result_2 = PageIDCache.get_for_slug('article', 'EXPORT_READINESS')
    assert result_2 == article_page.id

    # Check invalid get_for_slug()
    assert PageIDCache.get_for_slug('abc', 'IMPORT_NOT_READINESS') is None
Ejemplo n.º 2
0
    def populate(cls, *args, **kwargs):
        ids_by_path = {}
        ids_by_slug = {}

        # This value should be cached by Wagtail
        site_root_paths = Site.get_site_root_paths()
        for page in cls.get_population_queryset():
            # Path lookup keys must include the site id and url_path, minus
            # the site root path, which Page.get_url_parts() can give us

            # setting this prevents repeat cache lookups
            page._wagtail_cached_site_root_paths = site_root_paths
            url_parts = page.get_url_parts()
            if url_parts:
                key = cls.build_path_lookup_key(url_parts[0], url_parts[2])
                ids_by_path[key] = page.id

            # Slug lookup keys must include the service name, as well as the
            # slug, which we need to work out
            service_name = cls.get_service_name_for_page(page)
            if service_name:
                key = cls.build_slug_lookup_key(service_name, page.slug)
                ids_by_slug[key] = page.id

        page_ids = {
            cls.by_path_map_key: ids_by_path,
            cls.by_slug_map_key: ids_by_slug,
        }
        cls.cache.set(cls.cache_key,
                      page_ids,
                      timeout=settings.API_CACHE_EXPIRE_SECONDS)
        return page_ids
Ejemplo n.º 3
0
    def test_result_order_when_multiple_sites_share_the_same_root_page(self):
        result = Site.get_site_root_paths()

        # An entry for the default site should come first
        self.assertEqual(result[0][0], self.default_site.id)

        # Followed by entries for others in 'host' alphabetical order
        self.assertEqual(result[1][0], self.abc_site.id)
        self.assertEqual(result[2][0], self.def_site.id)
Ejemplo n.º 4
0
    def test_result_order_when_multiple_sites_share_the_same_root_page(self):
        result = Site.get_site_root_paths()

        # An entry for the default site should come first
        self.assertEqual(result[0][0], self.default_site.id)

        # Followed by entries for others in 'host' alphabetical order
        self.assertEqual(result[1][0], self.abc_site.id)
        self.assertEqual(result[2][0], self.def_site.id)
Ejemplo n.º 5
0
 def _run_test(
     self, url, expected_page, expected_num_queries, full_url_match_expected,
     accept_best_match=True, max_subsequent_route_failures=3
 ):
     request = self.rf.get(url)
     # Set these to improve efficiency
     request.site = self.site
     request._wagtail_cached_site_root_paths = Site.get_site_root_paths()
     # Run tests
     with self.assertNumQueries(expected_num_queries):
         page, full_url_match = derive_page(
             request,
             self.site,
             accept_best_match,
             max_subsequent_route_failures,
         )
         self.assertEqual(page, expected_page)
         self.assertIs(full_url_match, full_url_match_expected)
Ejemplo n.º 6
0
def external_link(request):
    initial_data = {
        'url': request.GET.get('link_url', ''),
        'link_text': request.GET.get('link_text', ''),
    }

    if request.method == 'POST':
        form = ExternalLinkChooserForm(request.POST,
                                       initial=initial_data,
                                       prefix='external-link-chooser')

        if form.is_valid():
            submitted_url = form.cleaned_data['url']
            result = {
                'url':
                submitted_url,
                'title':
                form.cleaned_data['link_text'].strip()
                or form.cleaned_data['url'],
                # If the user has explicitly entered / edited something in the link_text field,
                # always use that text. If not, we should favour keeping the existing link/selection
                # text, where applicable.
                # (Normally this will match the link_text passed in the URL here anyhow,
                # but that won't account for non-text content such as images.)
                'prefer_this_title_as_link_text': ('link_text'
                                                   in form.changed_data),
            }

            link_conversion = getattr(settings,
                                      'WAGTAILADMIN_EXTERNAL_LINK_CONVERSION',
                                      LINK_CONVERSION_ALL).lower()

            if link_conversion not in [
                    LINK_CONVERSION_ALL, LINK_CONVERSION_EXACT,
                    LINK_CONVERSION_CONFIRM
            ]:
                # We should not attempt to convert external urls to page links
                return render_modal_workflow(request,
                                             None,
                                             None,
                                             None,
                                             json_data={
                                                 'step':
                                                 'external_link_chosen',
                                                 'result': result
                                             })

            # Next, we should check if the url matches an internal page
            # Strip the url of its query/fragment link parameters - these won't match a page
            url_without_query = re.split(r"\?|#", submitted_url)[0]

            # Start by finding any sites the url could potentially match
            sites = getattr(request, '_wagtail_cached_site_root_paths', None)
            if sites is None:
                sites = Site.get_site_root_paths()

            match_relative_paths = submitted_url.startswith('/') and len(
                sites) == 1
            # We should only match relative urls if there's only a single site
            # Otherwise this could get very annoying accidentally matching coincidentally
            # named pages on different sites

            if match_relative_paths:
                possible_sites = [(pk, url_without_query)
                                  for pk, path, url, language_code in sites]
            else:
                possible_sites = [(pk, url_without_query[len(url):])
                                  for pk, path, url, language_code in sites
                                  if submitted_url.startswith(url)]

            # Loop over possible sites to identify a page match
            for pk, url in possible_sites:
                try:
                    route = Site.objects.get(pk=pk).root_page.specific.route(
                        request, [
                            component
                            for component in url.split('/') if component
                        ])

                    matched_page = route.page.specific

                    internal_data = {
                        'id':
                        matched_page.pk,
                        'parentId':
                        matched_page.get_parent().pk,
                        'adminTitle':
                        matched_page.draft_title,
                        'editUrl':
                        reverse('wagtailadmin_pages:edit',
                                args=(matched_page.pk, )),
                        'url':
                        matched_page.url
                    }

                    # Let's check what this page's normal url would be
                    normal_url = matched_page.get_url_parts(
                        request=request
                    )[-1] if match_relative_paths else matched_page.get_full_url(
                        request=request)

                    # If that's what the user provided, great. Let's just convert the external
                    # url to an internal link automatically unless we're set up tp manually check
                    # all conversions
                    if normal_url == submitted_url and link_conversion != LINK_CONVERSION_CONFIRM:
                        return render_modal_workflow(
                            request,
                            None,
                            None,
                            None,
                            json_data={
                                'step': 'external_link_chosen',
                                'result': internal_data
                            })
                    # If not, they might lose query parameters or routable page information

                    if link_conversion == LINK_CONVERSION_EXACT:
                        # We should only convert exact matches
                        continue

                    # Let's confirm the conversion with them explicitly
                    else:
                        return render_modal_workflow(
                            request,
                            'wagtailadmin/chooser/confirm_external_to_internal.html',
                            None, {
                                'submitted_url': submitted_url,
                                'internal_url': normal_url,
                                'page': matched_page.draft_title,
                            },
                            json_data={
                                'step': 'confirm_external_to_internal',
                                'external': result,
                                'internal': internal_data
                            })

                except Http404:
                    continue

            # Otherwise, with no internal matches, fall back to an external url
            return render_modal_workflow(request,
                                         None,
                                         None,
                                         None,
                                         json_data={
                                             'step': 'external_link_chosen',
                                             'result': result
                                         })
    else:
        form = ExternalLinkChooserForm(initial=initial_data,
                                       prefix='external-link-chooser')

    return render_modal_workflow(request,
                                 'wagtailadmin/chooser/external_link.html',
                                 None,
                                 shared_context(request, {
                                     'form': form,
                                 }),
                                 json_data={'step': 'external_link'})