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")
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)
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")
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" )
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")
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/")
def _setup(self): Page.objects.filter(id=2).delete() root = Page.get_first_root_node() homepage = HomePage( title="St Louis DSA", banner_title="Welcome to St Louis DSA!", mission_statement=fake.sentence(10), values_statement=fake.sentence(10), highlighted_campaign=f"{' '.join(fake.words(2)).title()} Campaign", highlighted_description=fake.paragraph(5), ) root.add_child(instance=homepage) site = Site( hostname="localhost", root_page=homepage, is_default_site=True, site_name="stldsa.org", ) site.save() newsindexpage = NewsIndexPage( title="Updates", slug="updates", show_in_menus=True, ) homepage.add_child(instance=newsindexpage) newsindexpage.has_children_in_menu = False newsindexpage.sub_menu = None NewsPage = apps.get_model("news.NewsPage") newspage = NewsPage( title=fake.sentence(), main_story_heading=fake.sentence(), main_story_copy=fake.paragraph(10), related_stories=[ ( "related_story", { "heading": fake.sentence(4), "copy": fake.paragraph(5), }, ), ( "related_story", { "heading": fake.sentence(4), "copy": fake.paragraph(4), }, ), ], show_in_menus=False, ) newsindexpage.add_child(instance=newspage) event_menu_page = EventsPage(title="Events", show_in_menus=True, link_url="/events/") homepage.add_child(instance=event_menu_page) formation_index = InfoPage(title="All Formation Groups", show_in_menus=True) homepage.add_child(instance=formation_index) for formation_type_name in [ "Priority Resolutions", "Committees", "Working Groups", "Caucuses", ]: formation_type = CommitteesPage( title=formation_type_name, slug=stringcase.spinalcase(formation_type_name), show_in_menus=True, ) formation_index.add_child(instance=formation_type) formation_list = CommitteeFactory.build_batch(4) for formation in formation_list: formation_type.add_child(instance=formation) revision = formation.save_revision() revision.publish() formation.save() future_event = Event( title="Event Title", description=fake.paragraph(), start=fake.future_datetime( end_date=datetime.timedelta(days=6), tzinfo=datetime.timezone.utc, ), formation=formation, ) future_event.save() revision = formation_type.save_revision() revision.publish() formation_type.save() formation_index.save() Group.objects.create(name="Members")
def browse(request, parent_page_id=None): # A missing or empty page_type parameter indicates 'all page types' # (i.e. descendants of wagtailcore.page) page_type_string = request.GET.get("page_type") or "wagtailcore.page" user_perm = request.GET.get("user_perms", False) try: desired_classes = page_models_from_string(page_type_string) except (ValueError, LookupError): raise Http404 # Find parent page if parent_page_id: parent_page = get_object_or_404(Page, id=parent_page_id) elif desired_classes == (Page, ): # Just use the root page parent_page = Page.get_first_root_node() else: # Find the highest common ancestor for the specific classes passed in # In many cases, such as selecting an EventPage under an EventIndex, # this will help the administrator find their page quicker. all_desired_pages = Page.objects.all().type(*desired_classes) parent_page = all_desired_pages.first_common_ancestor() parent_page = parent_page.specific # Get children of parent page (without streamfields) pages = parent_page.get_children().defer_streamfields().specific() # allow hooks to modify the queryset for hook in hooks.get_hooks("construct_page_chooser_queryset"): pages = hook(pages, request) # Filter them by page type if desired_classes != (Page, ): # restrict the page listing to just those pages that: # - are of the given content type (taking into account class inheritance) # - or can be navigated into (i.e. have children) choosable_pages = pages.type(*desired_classes) descendable_pages = pages.filter(numchild__gt=0) pages = choosable_pages | descendable_pages can_choose_root = request.GET.get("can_choose_root", False) target_pages = Page.objects.filter(pk__in=[ int(pk) for pk in request.GET.getlist("target_pages[]", []) if pk ]) match_subclass = request.GET.get("match_subclass", True) # Do permission lookups for this user now, instead of for every page. permission_proxy = UserPagePermissionsProxy(request.user) # Parent page can be chosen if it is a instance of desired_classes parent_page.can_choose = can_choose_page( parent_page, permission_proxy, desired_classes, can_choose_root, user_perm, target_pages=target_pages, match_subclass=match_subclass, ) parent_page.is_parent_page = True parent_page.can_descend = False selected_locale = None locale_options = [] show_locale_labels = getattr(settings, "WAGTAIL_I18N_ENABLED", False) if show_locale_labels: pages = pages.select_related("locale") if parent_page.is_root(): # 'locale' is the current value of the "Locale" selector in the UI if request.GET.get("locale"): selected_locale = get_object_or_404( Locale, language_code=request.GET["locale"]) active_locale_id = selected_locale.pk else: active_locale_id = Locale.get_active().pk # we are at the Root level, so get the locales from the current pages choose_url = reverse("wagtailadmin_choose_page") locale_options = [{ "locale": locale, "url": choose_url + "?" + urlencode({ "page_type": page_type_string, "locale": locale.language_code }), } for locale in Locale.objects.filter( pk__in=pages.values_list("locale_id")).exclude( pk=active_locale_id)] else: # We have a parent page (that is not the root page). Use its locale as the selected localer selected_locale = parent_page.locale # and get the locales based on its available translations locales_and_parent_pages = { item["locale"]: item["pk"] for item in Page.objects.translation_of(parent_page).values( "locale", "pk") } locales_and_parent_pages[selected_locale.pk] = parent_page.pk for locale in Locale.objects.filter( pk__in=list(locales_and_parent_pages.keys())).exclude( pk=selected_locale.pk): choose_child_url = reverse( "wagtailadmin_choose_page_child", args=[locales_and_parent_pages[locale.pk]], ) locale_options.append({ "locale": locale, "url": choose_child_url + "?" + urlencode({"page_type": page_type_string}), }) # finally, filter the browseable pages on the selected locale if selected_locale: pages = pages.filter(locale=selected_locale) # Pagination # We apply pagination first so we don't need to walk the entire list # in the block below paginator = Paginator(pages, per_page=25) pages = paginator.get_page(request.GET.get("p")) # Annotate each page with can_choose/can_decend flags for page in pages: page.can_choose = can_choose_page( page, permission_proxy, desired_classes, can_choose_root, user_perm, target_pages=target_pages, match_subclass=match_subclass, ) page.can_descend = page.get_children_count() page.is_parent_page = False table = PageChooserTable( [ PageTitleColumn("title", label=_("Title")), DateColumn( "updated", label=_("Updated"), width="12%", accessor="latest_revision_created_at", ), Column("type", label=_("Type"), width="12%", accessor="page_type_display_name"), PageStatusColumn("status", label=_("Status"), width="12%"), PageNavigateToChildrenColumn("children", label="", width="10%"), ], [parent_page] + list(pages), ) # Render context = shared_context( request, { "parent_page": parent_page, "parent_page_id": parent_page.pk, "table": table, "pagination_page": pages, "search_form": SearchForm(), "page_type_string": page_type_string, "page_type_names": [ desired_class.get_verbose_name() for desired_class in desired_classes ], "page_types_restricted": (page_type_string != "wagtailcore.page"), "show_locale_labels": show_locale_labels, "locale_options": locale_options, "selected_locale": selected_locale, }, ) return render_modal_workflow( request, "wagtailadmin/chooser/browse.html", None, context, json_data={ "step": "browse", "parent_page_id": context["parent_page_id"] }, )
def get_root_page(self): """ Returns the page that is used when the `&child_of=root` filter is used. """ return Page.get_first_root_node()
def test_empty_queryset(self): self.assertEqual(Page.get_first_root_node(), Page.objects.none().first_common_ancestor())
def test_all_pages_include_self_strict(self): self.assertEqual( Page.get_first_root_node(), Page.objects.first_common_ancestor(include_self=True, strict=True), )
def test_all_pages(self): self.assertEqual(Page.get_first_root_node(), Page.objects.first_common_ancestor())
def index(request, parent_page_id=None): if parent_page_id: parent_page = get_object_or_404(Page, id=parent_page_id) else: parent_page = Page.get_first_root_node() # This will always succeed because of the @user_passes_test above. root_page = get_explorable_root_page(request.user) # If this page isn't a descendant of the user's explorable root page, # then redirect to that explorable root page instead. if not (parent_page.pk == root_page.pk or parent_page.is_descendant_of(root_page)): return redirect("wagtailadmin_explore", root_page.pk) parent_page = parent_page.specific user_perms = UserPagePermissionsProxy(request.user) pages = (parent_page.get_children().prefetch_related( "content_type", "sites_rooted_here") & user_perms.explorable_pages()) # Get page ordering ordering = request.GET.get("ordering", "-latest_revision_created_at") if ordering not in [ "title", "-title", "content_type", "-content_type", "live", "-live", "latest_revision_created_at", "-latest_revision_created_at", "ord", ]: ordering = "-latest_revision_created_at" if ordering == "ord": # preserve the native ordering from get_children() pass elif ordering == "latest_revision_created_at": # order by oldest revision first. # Special case NULL entries - these should go at the top of the list. # Do this by annotating with Count('latest_revision_created_at'), # which returns 0 for these pages = pages.annotate( null_position=Count("latest_revision_created_at")).order_by( "null_position", "latest_revision_created_at") elif ordering == "-latest_revision_created_at": # order by oldest revision first. # Special case NULL entries - these should go at the end of the list. pages = pages.annotate( null_position=Count("latest_revision_created_at")).order_by( "-null_position", "-latest_revision_created_at") else: pages = pages.order_by(ordering) # Don't paginate if sorting by page order - all pages must be shown to # allow drag-and-drop reordering do_paginate = ordering != "ord" # We want specific page instances, but do not need streamfield values here pages = pages.defer_streamfields().specific() # allow hooks defer_streamfieldsyset for hook in hooks.get_hooks("construct_explorer_page_queryset"): pages = hook(parent_page, pages, request) # Annotate queryset with various states to be used later for performance optimisations if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True): pages = pages.prefetch_workflow_states() pages = pages.annotate_site_root_state().annotate_approved_schedule() # Pagination if do_paginate: paginator = Paginator(pages, per_page=50) pages = paginator.get_page(request.GET.get("p")) show_ordering_column = request.GET.get("ordering") == "ord" context = { "parent_page": parent_page.specific, "ordering": ordering, "pages": pages, "do_paginate": do_paginate, "locale": None, "translations": [], "show_ordering_column": show_ordering_column, "show_bulk_actions": not show_ordering_column, "show_locale_labels": False, } if getattr(settings, "WAGTAIL_I18N_ENABLED", False): if not parent_page.is_root(): context.update({ "locale": parent_page.locale, "translations": [{ "locale": translation.locale, "url": reverse("wagtailadmin_explore", args=[translation.id]), } for translation in parent_page.get_translations().only( "id", "locale").select_related("locale")], }) else: context["show_locale_labels"] = True return TemplateResponse(request, "wagtailadmin/pages/index.html", context)
def get_form_kwargs(self): ctx = super().get_form_kwargs() ctx["destination"] = self.destination or Page.get_first_root_node() ctx["target_parent_models"] = self.target_parent_models ctx["pages_to_move"] = self.pages_to_move return ctx
def get(self, request, parent_page_id=None): self.i18n_enabled = getattr(settings, "WAGTAIL_I18N_ENABLED", False) # A missing or empty page_type parameter indicates 'all page types' # (i.e. descendants of wagtailcore.page) page_type_string = request.GET.get("page_type") or "wagtailcore.page" user_perm = request.GET.get("user_perms", False) try: self.desired_classes = page_models_from_string(page_type_string) except (ValueError, LookupError): raise Http404 # Find parent page if parent_page_id: self.parent_page = get_object_or_404(Page, id=parent_page_id) elif self.desired_classes == (Page, ): # Just use the root page self.parent_page = Page.get_first_root_node() else: # Find the highest common ancestor for the specific classes passed in # In many cases, such as selecting an EventPage under an EventIndex, # this will help the administrator find their page quicker. all_desired_pages = Page.objects.all().type(*self.desired_classes) self.parent_page = all_desired_pages.first_common_ancestor() self.parent_page = self.parent_page.specific pages = self.get_object_list() pages = self.filter_object_list(pages) can_choose_root = request.GET.get("can_choose_root", False) target_pages = Page.objects.filter(pk__in=[ int(pk) for pk in request.GET.getlist("target_pages[]", []) if pk ]) match_subclass = request.GET.get("match_subclass", True) # Do permission lookups for this user now, instead of for every page. permission_proxy = UserPagePermissionsProxy(request.user) # Parent page can be chosen if it is a instance of desired_classes self.parent_page.can_choose = can_choose_page( self.parent_page, permission_proxy, self.desired_classes, can_choose_root, user_perm, target_pages=target_pages, match_subclass=match_subclass, ) self.parent_page.is_parent_page = True self.parent_page.can_descend = False selected_locale = None locale_options = [] if self.i18n_enabled: if self.parent_page.is_root(): # 'locale' is the current value of the "Locale" selector in the UI if request.GET.get("locale"): selected_locale = get_object_or_404( Locale, language_code=request.GET["locale"]) active_locale_id = selected_locale.pk else: active_locale_id = Locale.get_active().pk # we are at the Root level, so get the locales from the current pages choose_url = reverse("wagtailadmin_choose_page") locale_options = [{ "locale": locale, "url": choose_url + "?" + urlencode({ "page_type": page_type_string, "locale": locale.language_code, }), } for locale in Locale.objects.filter( pk__in=pages.values_list("locale_id")).exclude( pk=active_locale_id)] else: # We have a parent page (that is not the root page). Use its locale as the selected localer selected_locale = self.parent_page.locale # and get the locales based on its available translations locales_and_parent_pages = { item["locale"]: item["pk"] for item in Page.objects.translation_of( self.parent_page).values("locale", "pk") } locales_and_parent_pages[ selected_locale.pk] = self.parent_page.pk for locale in Locale.objects.filter( pk__in=list(locales_and_parent_pages.keys())).exclude( pk=selected_locale.pk): choose_child_url = reverse( "wagtailadmin_choose_page_child", args=[locales_and_parent_pages[locale.pk]], ) locale_options.append({ "locale": locale, "url": choose_child_url + "?" + urlencode({"page_type": page_type_string}), }) # finally, filter the browseable pages on the selected locale if selected_locale: pages = pages.filter(locale=selected_locale) # Pagination # We apply pagination first so we don't need to walk the entire list # in the block below paginator = Paginator(pages, per_page=25) pages = paginator.get_page(request.GET.get("p")) # Annotate each page with can_choose/can_decend flags for page in pages: page.can_choose = can_choose_page( page, permission_proxy, self.desired_classes, can_choose_root, user_perm, target_pages=target_pages, match_subclass=match_subclass, ) page.can_descend = page.get_children_count() page.is_parent_page = False table = PageChooserTable( self.columns, [self.parent_page] + list(pages), ) # Render context = shared_context( request, { "parent_page": self.parent_page, "parent_page_id": self.parent_page.pk, "table": table, "pagination_page": pages, "search_form": SearchForm(), "page_type_string": page_type_string, "page_type_names": [ desired_class.get_verbose_name() for desired_class in self.desired_classes ], "page_types_restricted": (page_type_string != "wagtailcore.page"), "show_locale_labels": self.i18n_enabled, "locale_options": locale_options, "selected_locale": selected_locale, }, ) return render_modal_workflow( request, "wagtailadmin/chooser/browse.html", None, context, json_data={ "step": "browse", "parent_page_id": context["parent_page_id"] }, )