diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 21c00475..e315d53d 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -32,6 +32,10 @@ jobs: - py310-dj40-wt30 - py310-dj40-wt40 - py310-dj40-wt41 + - py310-dj40-wt42 + - py310-dj41-wt40 + - py310-dj41-wt41 + - py310-dj41-wt42 - py38-dj32-wt215 - py38-dj32-wt216 - py38-dj32-wt30 @@ -40,7 +44,10 @@ jobs: - py38-dj40-wt216 - py38-dj40-wt30 - py38-dj40-wt40 - - py38-dj40-wt41 + - py38-dj40-wt40 + - py38-dj41-wt41 + - py38-dj41-wt42 + - py38-dj41-wt41 - py39-dj32-wt215 - py39-dj32-wt216 - py39-dj32-wt30 @@ -50,6 +57,9 @@ jobs: - py39-dj40-wt30 - py39-dj40-wt40 - py39-dj40-wt41 + - py39-dj41-wt40 + - py39-dj41-wt41 + - py39-dj41-wt42 include: - python-version: 3.8 tox_env: py38-dj32-wt215 @@ -69,6 +79,12 @@ jobs: tox_env: py38-dj40-wt40 - python-version: 3.8 tox_env: py38-dj40-wt41 + - python-version: 3.8 + tox_env: py38-dj41-wt40 + - python-version: 3.8 + tox_env: py38-dj41-wt41 + - python-version: 3.8 + tox_env: py38-dj41-wt42 - python-version: 3.9 tox_env: py39-dj32-wt215 - python-version: 3.9 @@ -87,6 +103,12 @@ jobs: tox_env: py39-dj40-wt40 - python-version: 3.9 tox_env: py39-dj40-wt41 + - python-version: 3.9 + tox_env: py39-dj41-wt40 + - python-version: 3.9 + tox_env: py39-dj41-wt41 + - python-version: 3.9 + tox_env: py39-dj41-wt42 - python-version: "3.10" tox_env: py310-dj32-wt215 - python-version: "3.10" @@ -105,6 +127,12 @@ jobs: tox_env: py310-dj40-wt40 - python-version: "3.10" tox_env: py310-dj40-wt41 + - python-version: "3.10" + tox_env: py310-dj41-wt40 + - python-version: "3.10" + tox_env: py310-dj41-wt41 + - python-version: "3.10" + tox_env: py310-dj41-wt42 steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/setup.py b/setup.py index 49b5ec43..7efc6f87 100644 --- a/setup.py +++ b/setup.py @@ -18,8 +18,9 @@ install_requires = [ - "wagtail>=2,<4.2", + "wagtail>=2,<4.3", "Unidecode>=0.04.14,<2.0", + "wagtail-generic-chooser>=0.5.0" ] documentation_extras = [ @@ -68,6 +69,7 @@ "Framework :: Django :: 2.2", "Framework :: Django :: 3.2", "Framework :: Django :: 4", + "Framework :: Django :: 4.1", "Framework :: Wagtail", "Framework :: Wagtail :: 2", "Framework :: Wagtail :: 3", diff --git a/tests/blocks/test_form_chooser_block.py b/tests/blocks/test_form_chooser_block.py index abe93854..af417427 100644 --- a/tests/blocks/test_form_chooser_block.py +++ b/tests/blocks/test_form_chooser_block.py @@ -14,15 +14,11 @@ def test_value_for_form(self): block = FormChooserBlock() self.assertEqual(block.value_for_form(self.form.pk), self.form.pk) - self.assertEqual(block.value_for_form(self.form), self.form.pk) + self.assertEqual(block.value_for_form(self.form), self.form) def test_value_from_form(self): block = FormChooserBlock() - # possibly a bug in wagtail as not choosing a value and submitting - # raises invalid literal for int() with base 10: '' - self.assertIsNone(block.value_from_form("")) - self.assertTrue( isinstance(block.value_from_form(self.form.pk), self.form.__class__) ) diff --git a/tests/hooks/test_process_form.py b/tests/hooks/test_process_form.py index 3244e35d..e07e14a8 100644 --- a/tests/hooks/test_process_form.py +++ b/tests/hooks/test_process_form.py @@ -1,12 +1,6 @@ from django.contrib.auth.models import AnonymousUser from django.test import override_settings from django.test.client import Client - -try: - from mock import patch -except ModuleNotFoundError: - from unittest.mock import patch - from wagtail.core.models import Page from wagtailstreamforms.models import Form @@ -14,6 +8,11 @@ from ..test_case import AppTestCase +try: + from mock import patch +except ModuleNotFoundError: + from unittest.mock import patch + class TestHook(AppTestCase): fixtures = ["test.json"] diff --git a/tox.ini b/tox.ini index 5826d425..0ab28f5c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,8 @@ [tox] envlist = flake8 - py{38,39,310}-dj{32}-wt{215,216,30,40,41} - py{38,39,310}-dj{40}-wt{216,30,40,41} + py{38,39,310}-dj{32}-wt{215,216,30,40,41,42} + py{38,39,310}-dj{40,41}-wt{216,30,40,41,42} [gh-actions] python = @@ -17,11 +17,13 @@ deps = mock dj32: Django>=3.2,<3.3 dj40: Django>=4.0,<4.1 + dj41: Django>=4.1,<4.2 wt215: wagtail>=2.15,<2.16 wt216: wagtail>=2.16,<2.17 wt30: wagtail>=3.0,<4.0 wt40: wagtail>=4.0,<4.1 wt41: wagtail>=4.1,<4.2 + wt42: wagtail>=4.2,<4.3 commands = coverage run manage.py test diff --git a/wagtailstreamforms/__init__.py b/wagtailstreamforms/__init__.py index e19448ec..71f74e75 100644 --- a/wagtailstreamforms/__init__.py +++ b/wagtailstreamforms/__init__.py @@ -2,6 +2,6 @@ # major.minor.patch.release.number # release must be one of alpha, beta, rc, or final -VERSION = (3, 21, 0, "final", 1) +VERSION = (3, 22, 0, "final", 1) __version__ = get_version(VERSION) diff --git a/wagtailstreamforms/blocks.py b/wagtailstreamforms/blocks.py index c314028d..b2dd0cf2 100644 --- a/wagtailstreamforms/blocks.py +++ b/wagtailstreamforms/blocks.py @@ -1,11 +1,12 @@ import uuid -from django import forms +from django.utils.functional import cached_property from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from wagtail.core import blocks from wagtailstreamforms.models import Form +from wagtailstreamforms.wagtail_hooks import WagtailStreamFormsChooser class InfoBlock(blocks.CharBlock): @@ -18,27 +19,16 @@ def render_form(self, value, prefix="", errors=None): class FormChooserBlock(blocks.ChooserBlock): - target_model = Form - widget = forms.Select - - def value_for_form(self, value): - if isinstance(value, self.target_model): - return value.pk - return value - - def value_from_form(self, value): - if value == "": - return None - return super().value_from_form(value) - - def to_python(self, value): - if value is None: - return value - else: - try: - return self.target_model.objects.get(pk=value) - except self.target_model.DoesNotExist: - return None + @cached_property + def target_model(self): + return Form + + @cached_property + def widget(self): + return WagtailStreamFormsChooser() + + def get_form_state(self, value): + return self.widget.get_value_data(value) class WagtailFormBlock(blocks.StructBlock): diff --git a/wagtailstreamforms/wagtail_hooks.py b/wagtailstreamforms/wagtail_hooks.py index a793a7ba..20842b38 100644 --- a/wagtailstreamforms/wagtail_hooks.py +++ b/wagtailstreamforms/wagtail_hooks.py @@ -4,6 +4,8 @@ from django.template.response import TemplateResponse from django.urls import include, path, reverse from django.utils.translation import gettext_lazy as _ +from generic_chooser.views import ModelChooserViewSet +from generic_chooser.widgets import AdminChooser from wagtail.admin import messages as wagtail_messages from wagtail.contrib.modeladmin.helpers import AdminURLHelper, ButtonHelper from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register @@ -85,7 +87,7 @@ def get_buttons_for_obj( ) ) - # users that can do any form actions can vies submissions + # users that can do any form actions can view submissions buttons.append( self.button( pk, @@ -245,3 +247,26 @@ def process_form(page, request, *args, **kwargs): return TemplateResponse( request, page.get_template(request, *args, **kwargs), context ) + + +class WagtailStreamFormsChooserViewSet(ModelChooserViewSet): + icon = "form" + model = Form + page_title = _("Choose a form") + per_page = 10 + + +class WagtailStreamFormsChooser(AdminChooser): + choose_one_text = _("Choose a form") + choose_another_text = _("Choose another form") + link_to_chosen_text = _("Edit this form") + model = Form + choose_modal_url_name = "wagtailstreamforms_chooser:choose" + icon = "form" + + +@hooks.register("register_admin_viewset") +def register_wagtailstreamforms_chooser_viewset(): + return WagtailStreamFormsChooserViewSet( + "wagtailstreamforms_chooser", url_prefix="wagtailstreamforms-chooser" + )