dnscms: hide drafts from search results
This commit is contained in:
@@ -1,6 +1,12 @@
|
|||||||
|
from django.apps import apps as django_apps
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
from grapple.registry import registry as grapple_registry
|
||||||
from wagtail import hooks
|
from wagtail import hooks
|
||||||
|
from wagtail.documents import get_document_model
|
||||||
|
from wagtail.images import get_image_model
|
||||||
|
from wagtail.models import Page
|
||||||
|
from wagtail.search.backends import get_search_backend
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("register_rich_text_features")
|
@hooks.register("register_rich_text_features")
|
||||||
@@ -8,6 +14,36 @@ def enable_additional_rich_text_features(features):
|
|||||||
features.default_features.extend(["h5", "h6", "blockquote"])
|
features.default_features.extend(["h5", "h6", "blockquote"])
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register("register_schema_query")
|
||||||
|
def filter_search_to_live_pages(query_mixins):
|
||||||
|
"""
|
||||||
|
Grapple's default `search` resolver hits every page regardless of publish
|
||||||
|
state, exposing drafts on the public API. Prepend a mixin so MRO picks our
|
||||||
|
`resolve_search`, which restricts Page subclasses to live + public.
|
||||||
|
"""
|
||||||
|
if not grapple_registry.class_models:
|
||||||
|
return
|
||||||
|
|
||||||
|
class SearchLivePublicMixin:
|
||||||
|
def resolve_search(self, info, **kwargs):
|
||||||
|
query = kwargs.get("query")
|
||||||
|
if not query:
|
||||||
|
return None
|
||||||
|
s = get_search_backend()
|
||||||
|
results = []
|
||||||
|
models = [get_document_model(), get_image_model()]
|
||||||
|
for app in grapple_registry.apps:
|
||||||
|
models += django_apps.all_models[app].values()
|
||||||
|
for model in models:
|
||||||
|
if issubclass(model, Page):
|
||||||
|
results += s.search(query, model.objects.live().public())
|
||||||
|
else:
|
||||||
|
results += s.search(query, model)
|
||||||
|
return results
|
||||||
|
|
||||||
|
query_mixins.insert(0, SearchLivePublicMixin)
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("construct_page_action_menu")
|
@hooks.register("construct_page_action_menu")
|
||||||
def make_publish_default_action(menu_items, request, context):
|
def make_publish_default_action(menu_items, request, context):
|
||||||
for index, item in enumerate(menu_items):
|
for index, item in enumerate(menu_items):
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
from wagtail.search.backends import get_search_backend
|
||||||
|
|
||||||
|
from tests.conftest import EventPageFactory, GenericPageFactory
|
||||||
|
|
||||||
|
|
||||||
|
SEARCH_QUERY = """
|
||||||
|
query Search($query: String) {
|
||||||
|
results: search(query: $query) {
|
||||||
|
__typename
|
||||||
|
... on PageInterface {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _index(page):
|
||||||
|
# Wagtail's post_save signal enqueues indexing via django-tasks, which isn't
|
||||||
|
# drained synchronously in tests. Call the backend directly so the page is
|
||||||
|
# findable through the live search code path.
|
||||||
|
get_search_backend().add(page)
|
||||||
|
|
||||||
|
|
||||||
|
def _titles_for(body, typename):
|
||||||
|
return [r["title"] for r in body["data"]["results"] if r["__typename"] == typename]
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_returns_live_generic_page(home_page, graphql_post):
|
||||||
|
page = GenericPageFactory(
|
||||||
|
parent=home_page,
|
||||||
|
title="PublishedGenericSearchToken",
|
||||||
|
slug="published-generic-search",
|
||||||
|
)
|
||||||
|
_index(page)
|
||||||
|
|
||||||
|
response, body = graphql_post(SEARCH_QUERY, {"query": "PublishedGenericSearchToken"})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "errors" not in body, body
|
||||||
|
assert "PublishedGenericSearchToken" in _titles_for(body, "GenericPage")
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_excludes_draft_generic_page(home_page, graphql_post):
|
||||||
|
page = GenericPageFactory(
|
||||||
|
parent=home_page,
|
||||||
|
title="DraftGenericSearchToken",
|
||||||
|
slug="draft-generic-search",
|
||||||
|
live=False,
|
||||||
|
)
|
||||||
|
_index(page)
|
||||||
|
|
||||||
|
response, body = graphql_post(SEARCH_QUERY, {"query": "DraftGenericSearchToken"})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "errors" not in body, body
|
||||||
|
assert "DraftGenericSearchToken" not in _titles_for(body, "GenericPage")
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_returns_live_event_page(home_page, event_index, graphql_post):
|
||||||
|
page = EventPageFactory(
|
||||||
|
parent=event_index,
|
||||||
|
title="PublishedEventSearchToken",
|
||||||
|
slug="published-event-search",
|
||||||
|
)
|
||||||
|
_index(page)
|
||||||
|
|
||||||
|
response, body = graphql_post(SEARCH_QUERY, {"query": "PublishedEventSearchToken"})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "errors" not in body, body
|
||||||
|
assert "PublishedEventSearchToken" in _titles_for(body, "EventPage")
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_excludes_draft_event_page(home_page, event_index, graphql_post):
|
||||||
|
page = EventPageFactory(
|
||||||
|
parent=event_index,
|
||||||
|
title="DraftEventSearchToken",
|
||||||
|
slug="draft-event-search",
|
||||||
|
live=False,
|
||||||
|
)
|
||||||
|
_index(page)
|
||||||
|
|
||||||
|
response, body = graphql_post(SEARCH_QUERY, {"query": "DraftEventSearchToken"})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "errors" not in body, body
|
||||||
|
assert "DraftEventSearchToken" not in _titles_for(body, "EventPage")
|
||||||
Reference in New Issue
Block a user