diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8874be..9cdf39d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: [3.7, 3.8, 3.9] + python: [3.8, 3.9] steps: - uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index bc657e7..ac562bc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,8 @@ wagtail_streamfield_index.egg-info media/ Pipfile Pipfile.lock +venv/ +.venv/ +build/ +__pycache__ +.vscode/ \ No newline at end of file diff --git a/setup.py b/setup.py index bc74ed7..60601ab 100644 --- a/setup.py +++ b/setup.py @@ -3,15 +3,15 @@ with open("README.md", "r") as fh: long_description = fh.read() -INSTALL_REQUIRES = ["django>=3.2", "Wagtail>=4.0"] +INSTALL_REQUIRES = ["django>=3.2", "Wagtail>=5.0.0", " wagtail < 6.0"] -TESTING_REQUIRES = ["pytest==5.2.1", "pytest-django==3.5.1", "pytest-pythonpath==0.7.3"] +TESTING_REQUIRES = ["pytest==6.2.5", "pytest-django==3.5.1", "pytest-pythonpath==0.7.3", "factory-boy>=3.2"] LINTING_REQUIRES = ["black==20.8b1", "flake8==3.7.8", "flake8-black==0.1.1", "isort==5.7.0"] setup( name="wagtail-streamfield-index", - version="0.0.4", + version="1.0.0", description="Indexing for Wagtail streamfields", author="Mike Monteith", author_email="", diff --git a/streamfieldindex/indexer.py b/streamfieldindex/indexer.py index f64ecfc..edd81e0 100644 --- a/streamfieldindex/indexer.py +++ b/streamfieldindex/indexer.py @@ -23,19 +23,20 @@ def index_page(page): # Clear the index for this specific page IndexEntry.objects.filter(page__id=page.id).delete() - for field in page._meta.fields: - if not isinstance(field, StreamField): - # We are only interested in streamfields. Skip over non-streamfield fields - continue + if page.live: # we dont want to index any draft/unpublished pages + for field in page._meta.fields: + if not isinstance(field, StreamField): + # We are only interested in streamfields. Skip over non-streamfield fields + continue - index_field(field, page) + index_field(field, page) def index_field(field, page): field_name = field.name streamvalue = getattr(page, field_name) - for (block, path) in flatten_streamfield(streamvalue): + for block, path in flatten_streamfield(streamvalue): field_name = field_name block_name = path[-1] diff --git a/streamfieldindex/models.py b/streamfieldindex/models.py index 2093faf..dcf1a81 100644 --- a/streamfieldindex/models.py +++ b/streamfieldindex/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.urls import reverse from wagtail.blocks import ListBlock, StreamBlock, StructBlock @@ -21,6 +22,9 @@ class IndexEntry(models.Model): page = models.ForeignKey("wagtailcore.Page", on_delete=models.CASCADE) + def get_edit_url(self): + return reverse("wagtailadmin_pages:edit", args=[self.page.id]) + def get_bound_block(self): field_value = getattr(self.page.specific, self.field_name) path = self.block_path.split("/") @@ -43,7 +47,7 @@ def get_sub_block(bound_block, path_list): next_block = bound_block.value[index] return get_sub_block(next_block, path_list) else: - raise Exception(f"We don't know how to iterate over block type {type(bound_block.block)}") + raise ValueError(f"We don't know how to iterate over block type {type(bound_block.block)}") first_index = path.pop(0) # The first index must always be a number, since it is a streamfield path.pop(0) # We can throw away the next path as it is just the block_type which we don't need @@ -51,7 +55,7 @@ def get_sub_block(bound_block, path_list): return get_sub_block(block, path) def __str__(self): - return f"" + return f"Streamfield index: {self.page.title} {self.field_name} {self.block_path}" # noqa E231 class Meta: verbose_name_plural = "Index Entries" diff --git a/streamfieldindex/wagtail_hooks.py b/streamfieldindex/wagtail_hooks.py index dbd47fe..c4233a4 100644 --- a/streamfieldindex/wagtail_hooks.py +++ b/streamfieldindex/wagtail_hooks.py @@ -1,7 +1,10 @@ +from django.urls import reverse from wagtail import hooks -from wagtail.signals import page_published +from wagtail.admin.admin_url_finder import ModelAdminURLFinder, register_admin_url_finder +from wagtail.signals import page_published, page_unpublished, post_page_move from .indexer import index_page +from .models import IndexEntry @hooks.register("after_create_page") @@ -14,8 +17,35 @@ def index_after_edit_page(request, page): index_page(page) +@hooks.register("after_copy_page") +def index_after_copy_page(request, page): + index_page(page) + + def post_publish(sender, instance, **kwargs): index_page(instance) +def index_post_page_move(sender, instance, **kwargs): + index_page(instance) + + +def index_post_unpublished(sender, instance, **kwargs): + index_page(instance) + + +class IndexEntryAdminURLFinder(ModelAdminURLFinder): + """ + Custom URL finder for IndexEntry model + https://github.com/gasman/wagtail/blob/9174db40746514b6fa6d792b25507571381c9255/wagtail/admin/admin_url_finder.py#L28 + """ + + def construct_edit_url(self, instance): + return reverse("wagtailadmin_pages:edit", args=[instance.page.id]) + + +register_admin_url_finder(IndexEntry, IndexEntryAdminURLFinder) + page_published.connect(post_publish) +page_unpublished.connect(index_post_unpublished) +post_page_move.connect(index_post_page_move) diff --git a/tests/test_wagtail_hooks.py b/tests/test_wagtail_hooks.py new file mode 100644 index 0000000..cf812c7 --- /dev/null +++ b/tests/test_wagtail_hooks.py @@ -0,0 +1,21 @@ +import pytest +from django.urls import reverse +from wagtail.test.utils.wagtail_factories import PageFactory +from wagtail.tests.utils import WagtailTestUtils + +import streamfieldindex +from streamfieldindex.wagtail_hooks import IndexEntryAdminURLFinder + + +@pytest.mark.django_db +class TestIndexEntryAdminURLFinder(WagtailTestUtils): + def test_construct_edit_url(self): + finder = IndexEntryAdminURLFinder() + instance = streamfieldindex.models.IndexEntry( + page=PageFactory(), + block_type="text", + block_value="Hello, world!", + block_path="content", + ) + expected_url = reverse("wagtailadmin_pages:edit", args=[instance.page.id]) + assert finder.construct_edit_url(instance) == expected_url