Beispiel #1
0
    def test_cant_move_pages_between_locales(self):
        user = get_user_model().objects.get(email="*****@*****.**")
        homepage = Page.objects.get(url_path="/home/").specific
        root = Page.objects.get(url_path="/").specific

        fr_locale = Locale.objects.create(language_code="fr")
        fr_page = root.add_child(instance=Page(
            title="French page",
            slug="french-page",
            locale=fr_locale,
        ))

        fr_homepage = root.add_child(instance=Page(
            title="French homepage",
            slug="french-homepage",
            locale=fr_locale,
        ))

        french_page_perms = fr_page.permissions_for_user(user)

        # fr_page can be moved into fr_homepage but not homepage
        self.assertFalse(french_page_perms.can_move_to(homepage))
        self.assertTrue(french_page_perms.can_move_to(fr_homepage))

        # All pages can be moved to the root, regardless what language they are
        self.assertTrue(french_page_perms.can_move_to(root))

        events_index = Page.objects.get(url_path="/home/events/")
        events_index_perms = events_index.permissions_for_user(user)
        self.assertTrue(events_index_perms.can_move_to(root))
Beispiel #2
0
def _page_urls_for_sites(page: Page, sites: Tuple[Site],
                         cache_target: Page) -> Set[Tuple[Site, str, str]]:
    urls = set()
    for site in sites:

        # use a `HttpRequest` to influence the return value
        request = get_dummy_request(site=site)
        # reuse cached site root paths if available
        if hasattr(cache_target, "_wagtail_cached_site_root_paths"):
            request._wagtail_cached_site_root_paths = (
                cache_target._wagtail_cached_site_root_paths)

        url_parts = page.get_url_parts(request)
        if url_parts is None:
            continue
        site_id, root_url, page_path = url_parts

        if page_path:
            for route_path in page.get_route_paths():
                normalized_route_path = Redirect.normalise_page_route_path(
                    route_path)
                old_path = Redirect.normalise_path(
                    page_path.rstrip("/") + (normalized_route_path or "/"))
                urls.add((site, old_path, normalized_route_path))

        # copy cached site root paths to `cache_target` to retain benefits
        cache_target._wagtail_cached_site_root_paths = (
            request._wagtail_cached_site_root_paths)

    return urls
Beispiel #3
0
 def test_change_root_page_locale_on_locale_deletion(self):
     """
     On deleting the locale used for the root page (but no 'real' pages), the
     root page should be reassigned to a new locale (the default one, if possible)
     """
     # change 'real' pages first
     Page.objects.filter(depth__gt=1).update(locale=Locale.objects.get(
         language_code="fr"))
     self.assertEqual(Page.get_first_root_node().locale.language_code, "en")
     Locale.objects.get(language_code="en").delete()
     self.assertEqual(Page.get_first_root_node().locale.language_code, "fr")
Beispiel #4
0
    def test_construct_queryset_hook(self):
        page = SimplePage(title="Test shown", content="hello")
        Page.get_first_root_node().add_child(instance=page)

        page_not_shown = SimplePage(title="Test not shown", content="hello")
        Page.get_first_root_node().add_child(instance=page_not_shown)

        def filter_pages(pages, request):
            return pages.filter(id=page.id)

        with self.register_hook("construct_page_chooser_queryset",
                                filter_pages):
            response = self.get()
        self.assertEqual(len(response.context["pages"]), 1)
        self.assertEqual(response.context["pages"][0].specific, page)
Beispiel #5
0
    def test_can_delete_default_locale_when_language_code_has_no_locale(self):
        Locale.objects.create(language_code="fr")

        self.assertTrue(Page.get_first_root_node().locale.language_code, "en")
        Page.objects.filter(depth__gt=1).delete()
        response = self.post()

        # Should redirect back to index
        self.assertRedirects(response, reverse("wagtaillocales:index"))

        # Check that the locale was deleted
        self.assertFalse(Locale.objects.filter(language_code="en").exists())

        # root node's locale should now have been reassigned to 'fr' despite that not matching
        # LANGUAGE_CODE (because it's the only remaining Locale record)
        self.assertTrue(Page.get_first_root_node().locale.language_code, "fr")
Beispiel #6
0
    def test_page_copy_post_new_parent(self):
        post_data = {
            "new_title": "Hello world 2",
            "new_slug": "hello-world-2",
            "new_parent_page": str(self.test_child_page.id),
            "copy_subpages": False,
            "publish_copies": False,
            "alias": False,
        }
        response = self.client.post(
            reverse("wagtailadmin_pages:copy", args=(self.test_page.id, )),
            post_data)

        # Check that the user was redirected to the new parents explore page
        self.assertRedirects(
            response,
            reverse("wagtailadmin_explore", args=(self.test_child_page.id, )))

        # Check that the page was copied to the correct place
        self.assertTrue(
            Page.objects.filter(slug="hello-world-2").first().get_parent(),
            msg=self.test_child_page,
        )

        # treebeard should report no consistency problems with the tree
        self.assertFalse(any(Page.find_problems()),
                         msg="treebeard found consistency problems")
Beispiel #7
0
    def test_submit_page_translation_view_test_post_multiple_locales(self):
        # Needs an extra page to hit recursive function
        en_blog_post_sub = Page(title="Blog post sub", slug="blog-post-sub")
        self.en_blog_post.add_child(instance=en_blog_post_sub)

        url = reverse("simple_translation:submit_page_translation",
                      args=(self.en_blog_post.id, ))
        de = Locale.objects.get(language_code="de").id
        fr = Locale.objects.get(language_code="fr").id
        data = {"locales": [de, fr], "include_subtree": True}
        self.login()

        with self.assertRaisesMessage(ParentNotTranslatedError, ""):
            self.client.post(url, data)

        url = reverse("simple_translation:submit_page_translation",
                      args=(self.en_blog_index.id, ))
        response = self.client.post(url, data)

        assert response.status_code == 302
        assert response.url == f"/admin/pages/{self.en_blog_index.get_parent().id}/"

        response = self.client.get(response.url)  # follow the redirect
        assert [msg.message for msg in response.context["messages"]
                ] == ["The page 'Blog' was successfully created in 2 locales"]
Beispiel #8
0
    def test_page_delete_notlive_post(self):
        # Same as above, but this makes sure the page_unpublished signal is not fired
        # when if the page is not live when it is deleted

        # Unpublish the page
        self.child_page.live = False
        self.child_page.save()

        # Connect a mock signal handler to page_unpublished signal
        mock_handler = mock.MagicMock()
        page_unpublished.connect(mock_handler)

        # Post
        response = self.client.post(
            reverse("wagtailadmin_pages:delete", args=(self.child_page.id, )))

        # Should be redirected to explorer page
        self.assertRedirects(
            response,
            reverse("wagtailadmin_explore", args=(self.root_page.id, )))

        # treebeard should report no consistency problems with the tree
        self.assertFalse(any(Page.find_problems()),
                         "treebeard found consistency problems")

        # Check that the page is gone
        self.assertEqual(
            Page.objects.filter(path__startswith=self.root_page.path,
                                slug="hello-world").count(),
            0,
        )

        # Check that the page_unpublished signal was not fired
        self.assertEqual(mock_handler.call_count, 0)
Beispiel #9
0
    def test_page_delete_post(self):
        # Connect a mock signal handler to page_unpublished signal
        mock_handler = mock.MagicMock()
        page_unpublished.connect(mock_handler)

        # Post
        response = self.client.post(
            reverse("wagtailadmin_pages:delete", args=(self.child_page.id,))
        )

        # Should be redirected to explorer page
        self.assertRedirects(
            response, reverse("wagtailadmin_explore", args=(self.root_page.id,))
        )

        # treebeard should report no consistency problems with the tree
        self.assertFalse(
            any(Page.find_problems()), "treebeard found consistency problems"
        )

        # Check that the page is gone
        self.assertEqual(
            Page.objects.filter(
                path__startswith=self.root_page.path, slug="hello-world"
            ).count(),
            0,
        )

        # Check that the page_unpublished signal was fired
        self.assertEqual(mock_handler.call_count, 1)
        mock_call = mock_handler.mock_calls[0][2]

        self.assertEqual(mock_call["sender"], self.child_page.specific_class)
        self.assertEqual(mock_call["instance"], self.child_page)
        self.assertIsInstance(mock_call["instance"], self.child_page.specific_class)
Beispiel #10
0
    def clean(self):
        cleaned_data = super().clean()
        if "slug" in self.cleaned_data:
            if not Page._slug_is_available(cleaned_data["slug"],
                                           self.parent_page, self.instance):
                self.add_error(
                    "slug",
                    forms.ValidationError(_("This slug is already in use")))

        # Check scheduled publishing fields
        go_live_at = cleaned_data.get("go_live_at")
        expire_at = cleaned_data.get("expire_at")

        # Go live must be before expire
        if go_live_at and expire_at:
            if go_live_at > expire_at:
                msg = _("Go live date/time must be before expiry date/time")
                self.add_error("go_live_at", forms.ValidationError(msg))
                self.add_error("expire_at", forms.ValidationError(msg))

        # Expire at must be in the future
        if expire_at and expire_at < timezone.now():
            self.add_error(
                "expire_at",
                forms.ValidationError(
                    _("Expiry date/time must be in the future")),
            )

        # Don't allow an existing first_published_at to be unset by clearing the field
        if ("first_published_at" in cleaned_data
                and not cleaned_data["first_published_at"]):
            del cleaned_data["first_published_at"]

        return cleaned_data
Beispiel #11
0
    def test_not_translation_of(self):
        en_homepage = Page.objects.get(url_path="/home/")

        # Create a translation of the homepage
        fr_locale = Locale.objects.create(language_code="fr")
        root_page = Page.objects.get(depth=1)
        fr_homepage = root_page.add_child(instance=Page(
            title="French homepage",
            slug="home-fr",
            locale=fr_locale,
            translation_key=en_homepage.translation_key,
        ))

        with self.assertNumQueries(1):
            translations = list(Page.objects.not_translation_of(en_homepage))

        # Check that every single page is in the queryset, except for fr_homepage
        for page in Page.objects.all():
            if page in [fr_homepage]:
                self.assertNotIn(page, translations)
            else:
                self.assertIn(page, translations)

        # Test with inclusive
        with self.assertNumQueries(1):
            translations = list(
                Page.objects.not_translation_of(en_homepage, inclusive=True))

        # Check that every single page is in the queryset, except for fr_homepage and en_homepage
        for page in Page.objects.all():
            if page in [en_homepage, fr_homepage]:
                self.assertNotIn(page, translations)
            else:
                self.assertIn(page, translations)
Beispiel #12
0
def move_confirm(request, page_to_move_id, destination_id):
    page_to_move = get_object_or_404(Page, id=page_to_move_id).specific
    # Needs .specific_deferred because the .get_admin_display_title method is called in template
    destination = get_object_or_404(Page, id=destination_id).specific_deferred

    if not Page._slug_is_available(
            page_to_move.slug, destination, page=page_to_move):
        messages.error(
            request,
            _("The slug '{0}' is already in use at the selected parent page. Make sure the slug is unique and try again"
              ).format(page_to_move.slug),
        )
        return redirect(
            "wagtailadmin_pages:move_choose_destination",
            page_to_move.id,
            destination.id,
        )

    for fn in hooks.get_hooks("before_move_page"):
        result = fn(request, page_to_move, destination)
        if hasattr(result, "status_code"):
            return result

    if request.method == "POST":
        # any invalid moves *should* be caught by the permission check in the action class,
        # so don't bother to catch InvalidMoveToDescendant
        action = MovePageAction(page_to_move,
                                destination,
                                pos="last-child",
                                user=request.user)
        action.execute()

        messages.success(
            request,
            _("Page '{0}' moved.").format(
                page_to_move.get_admin_display_title()),
            buttons=[
                messages.button(
                    reverse("wagtailadmin_pages:edit",
                            args=(page_to_move.id, )),
                    _("Edit"),
                )
            ],
        )

        for fn in hooks.get_hooks("after_move_page"):
            result = fn(request, page_to_move)
            if hasattr(result, "status_code"):
                return result

        return redirect("wagtailadmin_explore", destination.id)

    return TemplateResponse(
        request,
        "wagtailadmin/pages/confirm_move.html",
        {
            "page_to_move": page_to_move,
            "destination": destination,
        },
    )
Beispiel #13
0
    def setUp(self):
        self.root_page = Page.objects.get(depth=1)
        self.home_page = Page.objects.get(depth=2)

        self.second_home_page = self.root_page.add_child(
            instance=Page(title="Second homepage", slug="home-1")
        )
Beispiel #14
0
    def test_page_copy_no_publish_permission_post_copy_subpages_publish_copies(self):
        # This tests that unprivileged users cannot publish copied pages even if they hack their browser

        # Turn user into an editor who can add pages but not publish them
        self.user.is_superuser = False
        self.user.groups.add(
            Group.objects.get(name="Editors"),
        )
        self.user.save()

        # Post
        post_data = {
            "new_title": "Hello world 2",
            "new_slug": "hello-world-2",
            "new_parent_page": str(self.root_page.id),
            "copy_subpages": True,
            "publish_copies": True,
            "alias": False,
        }
        response = self.client.post(
            reverse("wagtailadmin_pages:copy", args=(self.test_page.id,)), post_data
        )

        # Check that the user was redirected to the parents explore page
        self.assertRedirects(
            response, reverse("wagtailadmin_explore", args=(self.root_page.id,))
        )

        # Get copy
        page_copy = self.root_page.get_children().filter(slug="hello-world-2").first()

        # Check that the copy exists
        self.assertIsNotNone(page_copy)

        # Check that the copy is not live
        self.assertFalse(page_copy.live)

        # Check that the owner of the page is set correctly
        self.assertEqual(page_copy.owner, self.user)

        # Check that the children were copied
        self.assertEqual(page_copy.get_children().count(), 2)

        # Check the the child pages
        # Neither of them should be live
        child_copy = page_copy.get_children().filter(slug="child-page").first()
        self.assertIsNotNone(child_copy)
        self.assertFalse(child_copy.live)

        unpublished_child_copy = (
            page_copy.get_children().filter(slug="unpublished-child-page").first()
        )
        self.assertIsNotNone(unpublished_child_copy)
        self.assertFalse(unpublished_child_copy.live)

        # treebeard should report no consistency problems with the tree
        self.assertFalse(
            any(Page.find_problems()), msg="treebeard found consistency problems"
        )
Beispiel #15
0
def create_redirects(page: Page, page_old: Page,
                     sites: Iterable[Site]) -> None:
    url_path_length = len(page.url_path)
    sites = tuple(sites)

    if not sites:
        return None

    logger.info(f"Creating redirects for page: '{page}' id={page.id}")

    # For bulk-creating redirects in batches
    batch = BatchRedirectCreator(max_size=2000, ignore_conflicts=True)

    # Treat the page that was updated / moved separately to it's decendants,
    # because there may be changes to fields other than `slug` or `url_path`
    # that impact the URL.
    old_urls = _page_urls_for_sites(page_old, sites, cache_target=page)
    new_urls = _page_urls_for_sites(page, sites, cache_target=page)

    # Add redirects for urls that have changed
    changed_urls = old_urls - new_urls
    for site, old_path, route_path in changed_urls:
        batch.add(
            old_path=old_path,
            site=site,
            redirect_page=page,
            redirect_page_route_path=route_path,
            automatically_created=True,
        )

    # Now, repeat the process for each descendant page.
    # Only the `url_path` value of descendants should have been affected by the
    # change, so we can use in-memory manipulation of `url_path` to figure out what
    # the old URLS were

    for descendant in (page.get_descendants().live().defer_streamfields().
                       specific().iterator()):
        new_urls = _page_urls_for_sites(descendant, sites, cache_target=page)

        # Restore old 'url_path' value on in-memory instance
        descendant.url_path = page_old.url_path + descendant.url_path[
            url_path_length:]

        old_urls = _page_urls_for_sites(descendant, sites, cache_target=page)

        # Add redirects for urls that have changed
        changed_urls = old_urls - new_urls
        for site, old_path, route_path in changed_urls:
            batch.add(
                old_path=old_path,
                site=site,
                redirect_page=descendant,
                redirect_page_route_path=route_path,
                automatically_created=True,
            )

    # Process the final batch
    batch.process()
    logger.info(batch.get_summary())
Beispiel #16
0
    def test_bulk_delete_notlive_post(self):
        # Same as above, but this makes sure the page_unpublished signal is not fired
        # for the page that is not live when it is deleted

        # Unpublish the first child page
        page_to_be_unpublished = self.pages_to_be_deleted[0]
        page_to_be_unpublished.unpublish(user=self.user)

        # Connect a mock signal handler to page_unpublished signal
        mock_handler = mock.MagicMock()
        page_unpublished.connect(mock_handler)

        # Post
        response = self.client.post(self.url)

        # Should be redirected to explorer page
        self.assertEqual(response.status_code, 302)

        # treebeard should report no consistency problems with the tree
        self.assertFalse(any(Page.find_problems()),
                         "treebeard found consistency problems")

        # Check that the child pages to be deleted are gone
        for child_page in self.pages_to_be_deleted:
            self.assertFalse(
                SimplePage.objects.filter(id=child_page.id).exists())

        # Check that the child pages not to be deleted remain
        for child_page in self.pages_not_to_be_deleted:
            self.assertTrue(
                SimplePage.objects.filter(id=child_page.id).exists())

        # Check that the page_unpublished signal was not fired
        num_descendants = sum(
            len(v) for v in self.grandchildren_pages.values())
        self.assertEqual(mock_handler.call_count,
                         len(self.pages_to_be_deleted) + num_descendants - 1)

        # check that only signals for other pages are fired
        i = 0
        for child_page in self.pages_to_be_deleted:
            if child_page.id != page_to_be_unpublished.id:
                mock_call = mock_handler.mock_calls[i][2]
                i += 1
                self.assertEqual(mock_call["sender"],
                                 child_page.specific_class)
                self.assertEqual(mock_call["instance"], child_page)
                self.assertIsInstance(mock_call["instance"],
                                      child_page.specific_class)
            for grandchildren_page in self.grandchildren_pages.get(
                    child_page, []):
                mock_call = mock_handler.mock_calls[i][2]
                i += 1
                self.assertEqual(mock_call["sender"],
                                 grandchildren_page.specific_class)
                self.assertEqual(mock_call["instance"], grandchildren_page)
                self.assertIsInstance(mock_call["instance"],
                                      grandchildren_page.specific_class)
Beispiel #17
0
    def test_subpage_deletion(self):
        # Connect mock signal handlers to page_unpublished, pre_delete and post_delete signals
        unpublish_signals_received = []
        pre_delete_signals_received = []
        post_delete_signals_received = []

        def page_unpublished_handler(sender, instance, **kwargs):
            unpublish_signals_received.append((sender, instance.id))

        def pre_delete_handler(sender, instance, **kwargs):
            pre_delete_signals_received.append((sender, instance.id))

        def post_delete_handler(sender, instance, **kwargs):
            post_delete_signals_received.append((sender, instance.id))

        page_unpublished.connect(page_unpublished_handler)
        pre_delete.connect(pre_delete_handler)
        post_delete.connect(post_delete_handler)

        # Post
        response = self.client.post(
            reverse("wagtailadmin_pages:delete", args=(self.child_index.id, )))

        # Should be redirected to explorer page
        self.assertRedirects(
            response,
            reverse("wagtailadmin_explore", args=(self.root_page.id, )))

        # treebeard should report no consistency problems with the tree
        self.assertFalse(any(Page.find_problems()),
                         "treebeard found consistency problems")

        # Check that the page is gone
        self.assertFalse(
            StandardIndex.objects.filter(id=self.child_index.id).exists())
        self.assertFalse(Page.objects.filter(id=self.child_index.id).exists())

        # Check that the subpage is also gone
        self.assertFalse(
            StandardChild.objects.filter(id=self.grandchild_page.id).exists())
        self.assertFalse(
            Page.objects.filter(id=self.grandchild_page.id).exists())

        # Check that the signals were fired for both pages
        self.assertIn((StandardIndex, self.child_index.id),
                      unpublish_signals_received)
        self.assertIn((StandardChild, self.grandchild_page.id),
                      unpublish_signals_received)

        self.assertIn((StandardIndex, self.child_index.id),
                      pre_delete_signals_received)
        self.assertIn((StandardChild, self.grandchild_page.id),
                      pre_delete_signals_received)

        self.assertIn((StandardIndex, self.child_index.id),
                      post_delete_signals_received)
        self.assertIn((StandardChild, self.grandchild_page.id),
                      post_delete_signals_received)
Beispiel #18
0
    def test_issue_2599(self):
        homepage = Page.objects.get(id=2)

        child1 = Page(title="child1")
        homepage.add_child(instance=child1)
        child2 = Page(title="child2")
        homepage.add_child(instance=child2)

        child1.delete()

        self.login()
        post_data = {
            "title": "New page!",
            "content": "Some content",
            "slug": "hello-world",
            "action-submit": "Submit",
        }
        preview_url = reverse(
            "wagtailadmin_pages:preview_on_add",
            args=("tests", "simplepage", homepage.id),
        )
        response = self.client.post(preview_url, post_data)

        # Check the JSON response
        self.assertEqual(response.status_code, 200)
        self.assertJSONEqual(
            response.content.decode(),
            {
                "is_valid": True,
                "is_available": True
            },
        )

        response = self.client.get(preview_url)

        # Check the HTML response
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "tests/simple_page.html")
        self.assertContains(response, "New page!")

        # Check that the treebeard attributes were set correctly on the page object
        self.assertEqual(response.context["self"].depth, homepage.depth + 1)
        self.assertTrue(response.context["self"].path.startswith(
            homepage.path))
        self.assertEqual(response.context["self"].get_parent(), homepage)
Beispiel #19
0
    def get_actionable_objects(self):
        objects, objects_without_access = super().get_actionable_objects()
        request = self.request

        if objects:
            self.target_parent_models = set(
                objects[0].specific_class.allowed_parent_page_models())
            for obj in objects:
                self.target_parent_models.intersection_update(
                    set(obj.specific_class.allowed_parent_page_models()))

        self.pages_to_move = [page.id for page in objects]

        if self.cleaned_form is None:
            if len(self.target_parent_models) == 0:
                return [], {
                    **objects_without_access,
                    "pages_without_common_parent_page": [{
                        "item":
                        page,
                        "can_edit":
                        page.permissions_for_user(
                            self.request.user).can_edit(),
                    } for page in objects],
                }
            return objects, objects_without_access

        destination = self.cleaned_form.cleaned_data["chooser"]
        pages = []
        pages_without_destination_access = []
        pages_with_duplicate_slugs = []

        for page in objects:
            if not page.permissions_for_user(
                    request.user).can_move_to(destination):
                pages_without_destination_access.append(page)
            elif not Page._slug_is_available(page.slug, destination,
                                             page=page):
                pages_with_duplicate_slugs.append(page)
            else:
                pages.append(page)

        return pages, {
            **objects_without_access,
            "pages_without_destination_access": [{
                "item":
                page,
                "can_edit":
                page.permissions_for_user(self.request.user).can_edit(),
            } for page in pages_without_destination_access],
            "pages_with_duplicate_slugs": [{
                "item":
                page,
                "can_edit":
                page.permissions_for_user(self.request.user).can_edit(),
            } for page in pages_with_duplicate_slugs],
        }
Beispiel #20
0
    def test_page_copy_alias_post_copy_subpages(self):
        post_data = {
            "new_title": "Hello world 2",
            "new_slug": "hello-world-2",
            "new_parent_page": str(self.root_page.id),
            "copy_subpages": True,
            "publish_copies": False,
            "alias": True,
        }
        response = self.client.post(
            reverse("wagtailadmin_pages:copy", args=(self.test_page.id,)), post_data
        )

        # Check that the user was redirected to the parents explore page
        self.assertRedirects(
            response, reverse("wagtailadmin_explore", args=(self.root_page.id,))
        )

        # Get copy
        page_copy = self.root_page.get_children().get(slug="hello-world-2")

        # Check the copy is an alias of the original
        self.assertEqual(page_copy.alias_of, self.test_page.page_ptr)

        # Check that the copy is live
        # Note: publish_copies is ignored. Alias pages always keep the same state as their original
        self.assertTrue(page_copy.live)
        self.assertFalse(page_copy.has_unpublished_changes)

        # Check that the owner of the page is set correctly
        self.assertEqual(page_copy.owner, self.user)

        # Check that the children were copied
        self.assertEqual(page_copy.get_children().count(), 2)

        # Check the the child pages
        # Neither of them should be live
        child_copy = page_copy.get_children().filter(slug="child-page").first()
        self.assertIsNotNone(child_copy)
        self.assertEqual(child_copy.alias_of, self.test_child_page.page_ptr)
        self.assertTrue(child_copy.live)
        self.assertFalse(child_copy.has_unpublished_changes)

        unpublished_child_copy = (
            page_copy.get_children().filter(slug="unpublished-child-page").first()
        )
        self.assertIsNotNone(unpublished_child_copy)
        self.assertEqual(
            unpublished_child_copy.alias_of, self.test_unpublished_child_page.page_ptr
        )
        self.assertFalse(unpublished_child_copy.live)
        self.assertTrue(unpublished_child_copy.has_unpublished_changes)

        # treebeard should report no consistency problems with the tree
        self.assertFalse(
            any(Page.find_problems()), msg="treebeard found consistency problems"
        )
Beispiel #21
0
    def test_can_delete_default_locale(self):
        # The presence of the locale on the root page node (if that's the only thing using the
        # locale) should not prevent deleting it

        for lang in ("fr", "de", "pl", "ja"):
            Locale.objects.create(language_code=lang)

        self.assertTrue(Page.get_first_root_node().locale.language_code, "en")
        Page.objects.filter(depth__gt=1).delete()
        response = self.post()

        # Should redirect back to index
        self.assertRedirects(response, reverse("wagtaillocales:index"))

        # Check that the locale was deleted
        self.assertFalse(Locale.objects.filter(language_code="en").exists())

        # root node's locale should now have been reassigned to the one matching the current
        # LANGUAGE_CODE
        self.assertTrue(Page.get_first_root_node().locale.language_code, "de")
Beispiel #22
0
    def setUpClass(cls):
        super().setUpClass()

        cls.test_page = SimplePage(title="test", slug="test", content="test")
        cls.wagtail_root = Page.get_first_root_node()
        cls.wagtail_root.add_child(instance=cls.test_page)

        cls.test_page_group = Group.objects.create(name="Test page")
        GroupPagePermission.objects.create(
            group=cls.test_page_group, page=cls.test_page, permission_type="edit"
        )
Beispiel #23
0
    def setUp(self):
        self.site_2_page = SimplePage(
            title="Site 2 page",
            slug="site_2_page",
            content="Hello",
        )
        Page.get_first_root_node().add_child(instance=self.site_2_page)
        self.site_2_subpage = SimplePage(
            title="Site 2 subpage",
            slug="site_2_subpage",
            content="Hello again",
        )
        self.site_2_page.add_child(instance=self.site_2_subpage)

        self.site_2 = Site.objects.create(
            hostname="example.com",
            port=8080,
            root_page=Page.objects.get(pk=self.site_2_page.pk),
            is_default_site=False,
        )
        self.about_us_page = SimplePage.objects.get(url_path="/home/about-us/")
Beispiel #24
0
def autocreate_redirects_on_slug_change(instance_before: Page, instance: Page,
                                        **kwargs):
    # NB: `page_slug_changed` provides specific page instances,
    # so we do not need to 'upcast' them for create_redirects here

    if not getattr(settings, "WAGTAILREDIRECTS_AUTO_CREATE", True):
        return None

    # Determine sites to create redirects for
    sites = Site.objects.filter(id__in=[
        option.site_id for option in instance._get_relevant_site_root_paths(
            cache_object=instance)
    ]).exclude(root_page=instance)

    create_redirects(page=instance, page_old=instance_before, sites=sites)
Beispiel #25
0
    def setUp(self):
        root = Page.objects.first()
        other_home = Page(title="Other Root")
        root.add_child(instance=other_home)

        self.default_site = Site.objects.get(is_default_site=True)
        self.default_settings = TestSiteSetting.objects.create(
            title="Site title",
            email="*****@*****.**",
            site=self.default_site)

        self.other_site = Site.objects.create(hostname="other",
                                              root_page=other_home)
        self.other_settings = TestSiteSetting.objects.create(
            title="Other title", email="*****@*****.**", site=self.other_site)
Beispiel #26
0
    def test_bulk_delete_post(self):
        # Connect a mock signal handler to page_unpublished signal
        mock_handler = mock.MagicMock()
        page_unpublished.connect(mock_handler)

        # Post
        response = self.client.post(self.url)

        # Should be redirected to explorer page
        self.assertEqual(response.status_code, 302)

        # treebeard should report no consistency problems with the tree
        self.assertFalse(any(Page.find_problems()),
                         "treebeard found consistency problems")

        # Check that the child pages to be deleted are gone
        for child_page in self.pages_to_be_deleted:
            self.assertFalse(
                SimplePage.objects.filter(id=child_page.id).exists())

        # Check that the child pages not to be deleted remain
        for child_page in self.pages_not_to_be_deleted:
            self.assertTrue(
                SimplePage.objects.filter(id=child_page.id).exists())

        # Check that the page_unpublished signal was fired for all pages
        num_descendants = sum(
            len(i) for i in self.grandchildren_pages.values())
        self.assertEqual(mock_handler.call_count,
                         len(self.pages_to_be_deleted) + num_descendants)

        i = 0
        for child_page in self.pages_to_be_deleted:
            mock_call = mock_handler.mock_calls[i][2]
            i += 1
            self.assertEqual(mock_call["sender"], child_page.specific_class)
            self.assertEqual(mock_call["instance"], child_page)
            self.assertIsInstance(mock_call["instance"],
                                  child_page.specific_class)
            for grandchildren_page in self.grandchildren_pages.get(
                    child_page, []):
                mock_call = mock_handler.mock_calls[i][2]
                i += 1
                self.assertEqual(mock_call["sender"],
                                 grandchildren_page.specific_class)
                self.assertEqual(mock_call["instance"], grandchildren_page)
                self.assertIsInstance(mock_call["instance"],
                                      grandchildren_page.specific_class)
Beispiel #27
0
 def test_slugurl_tag_returns_url_for_current_site(self):
     home_page = Page.objects.get(url_path="/home/")
     new_home_page = home_page.copy(
         update_attrs={"title": "New home page", "slug": "new-home"}
     )
     second_site = Site.objects.create(
         hostname="site2.example.com", root_page=new_home_page
     )
     # Add a page to the new site that has a slug that is the same as one on
     # the first site, but is in a different position in the treeself.
     new_christmas_page = Page(title="Christmas", slug="christmas")
     new_home_page.add_child(instance=new_christmas_page)
     request = HttpRequest()
     request.META["HTTP_HOST"] = second_site.hostname
     request.META["SERVER_PORT"] = second_site.port
     url = slugurl(context=template.Context({"request": request}), slug="christmas")
     self.assertEqual(url, "/christmas/")
Beispiel #28
0
    def test_page_copy_post(self):
        post_data = {
            "new_title": "Hello world 2",
            "new_slug": "hello-world-2",
            "new_parent_page": str(self.root_page.id),
            "copy_subpages": False,
            "publish_copies": False,
            "alias": False,
        }
        response = self.client.post(
            reverse("wagtailadmin_pages:copy", args=(self.test_page.id, )),
            post_data)

        # Check that the user was redirected to the parents explore page
        self.assertRedirects(
            response,
            reverse("wagtailadmin_explore", args=(self.root_page.id, )))

        # Get copy
        page_copy = self.root_page.get_children().filter(
            slug="hello-world-2").first()

        # Check that the copy exists
        self.assertIsNotNone(page_copy)

        # Check that the copy is not live
        self.assertFalse(page_copy.live)
        self.assertTrue(page_copy.has_unpublished_changes)

        # Check that the owner of the page is set correctly
        self.assertEqual(page_copy.owner, self.user)

        # Check that the children were not copied
        self.assertEqual(page_copy.get_children().count(), 0)

        # treebeard should report no consistency problems with the tree
        self.assertFalse(any(Page.find_problems()),
                         msg="treebeard found consistency problems")
Beispiel #29
0
    def test_no_redirects_created_when_pages_are_moved_to_a_different_site(
            self):

        # Add a new home page
        homepage_2 = Page(
            title="Second home",
            slug="second-home",
        )
        root_page = Page.objects.get(depth=1)
        root_page.add_child(instance=homepage_2)

        # Create a site with the above as the root_page
        Site.objects.create(
            root_page=homepage_2,
            hostname="newsite.com",
            port=80,
        )

        # Move the event index to the new site
        self.event_index.move(homepage_2, pos="last-child")

        # No redirects should have been created
        self.assertFalse(Redirect.objects.exists())
Beispiel #30
0
    def test_translation_of(self):
        en_homepage = Page.objects.get(url_path="/home/")

        # Create a translation of the homepage
        fr_locale = Locale.objects.create(language_code="fr")
        root_page = Page.objects.get(depth=1)
        fr_homepage = root_page.add_child(instance=Page(
            title="French homepage",
            slug="home-fr",
            locale=fr_locale,
            translation_key=en_homepage.translation_key,
        ))

        with self.assertNumQueries(1):
            translations = Page.objects.translation_of(en_homepage)
            self.assertListEqual(list(translations), [fr_homepage])

        # Now test with inclusive
        with self.assertNumQueries(1):
            translations = Page.objects.translation_of(
                en_homepage, inclusive=True).order_by("id")
            self.assertListEqual(list(translations),
                                 [en_homepage, fr_homepage])