wagtail 6.2.2__py3-none-any.whl → 6.3rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_for_translation.py +6 -0
  3. wagtail/actions/publish_revision.py +3 -3
  4. wagtail/admin/action_menu.py +5 -3
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/icons.py +2 -6
  7. wagtail/admin/locale/cy/LC_MESSAGES/django.mo +0 -0
  8. wagtail/admin/locale/cy/LC_MESSAGES/django.po +32 -0
  9. wagtail/admin/locale/dv/LC_MESSAGES/django.mo +0 -0
  10. wagtail/admin/locale/dv/LC_MESSAGES/django.po +28 -0
  11. wagtail/admin/locale/en/LC_MESSAGES/django.po +451 -485
  12. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +7 -7
  13. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  14. wagtail/admin/locale/sl/LC_MESSAGES/django.po +150 -0
  15. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.mo +0 -0
  16. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.po +9 -2
  17. wagtail/admin/locale/ug/LC_MESSAGES/django.mo +0 -0
  18. wagtail/admin/locale/ug/LC_MESSAGES/django.po +3250 -196
  19. wagtail/admin/localization.py +12 -2
  20. wagtail/admin/panels/model_utils.py +1 -1
  21. wagtail/admin/site_summary.py +0 -2
  22. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  23. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  24. wagtail/admin/static/wagtailadmin/images/email-header.jpg +0 -0
  25. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +12 -0
  28. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  30. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  31. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
  34. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  37. wagtail/admin/staticfiles.py +6 -4
  38. wagtail/admin/templates/wagtailadmin/account/account.html +42 -59
  39. wagtail/admin/templates/wagtailadmin/admin_base.html +0 -28
  40. wagtail/admin/templates/wagtailadmin/bulk_actions/footer.html +1 -1
  41. wagtail/admin/templates/wagtailadmin/chooser/_search_results.html +7 -5
  42. wagtail/admin/templates/wagtailadmin/chooser/tables/page_navigate_to_children_cell.html +1 -1
  43. wagtail/admin/templates/wagtailadmin/generic/chooser/results.html +7 -5
  44. wagtail/admin/templates/wagtailadmin/generic/edit.html +0 -8
  45. wagtail/admin/templates/wagtailadmin/generic/form.html +60 -17
  46. wagtail/admin/templates/wagtailadmin/generic/index.html +17 -0
  47. wagtail/admin/templates/wagtailadmin/generic/index_results.html +9 -35
  48. wagtail/admin/templates/wagtailadmin/generic/inspect.html +2 -21
  49. wagtail/admin/templates/wagtailadmin/generic/listing.html +11 -17
  50. wagtail/admin/templates/wagtailadmin/generic/listing_results.html +19 -1
  51. wagtail/admin/templates/wagtailadmin/home/account_summary.html +26 -0
  52. wagtail/admin/templates/wagtailadmin/home/locked_pages.html +28 -18
  53. wagtail/admin/templates/wagtailadmin/home/recent_edits.html +28 -17
  54. wagtail/admin/templates/wagtailadmin/home/site_summary_pages.html +2 -2
  55. wagtail/admin/templates/wagtailadmin/home/upgrade_notification.html +35 -13
  56. wagtail/admin/templates/wagtailadmin/home/user_objects_in_workflow_moderation.html +28 -18
  57. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +43 -32
  58. wagtail/admin/templates/wagtailadmin/home.html +22 -5
  59. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -1
  60. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu.html +1 -11
  61. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu_item.html +1 -6
  62. wagtail/admin/templates/wagtailadmin/pages/action_menu/page_locked.html +1 -1
  63. wagtail/admin/templates/wagtailadmin/pages/action_menu/publish.html +1 -1
  64. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +1 -1
  65. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_delete.html +12 -6
  66. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_move.html +12 -7
  67. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_publish.html +17 -11
  68. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_unpublish.html +15 -9
  69. wagtail/admin/templates/wagtailadmin/pages/confirm_delete.html +9 -9
  70. wagtail/admin/templates/wagtailadmin/pages/confirm_move.html +2 -2
  71. wagtail/admin/templates/wagtailadmin/pages/confirm_unpublish.html +4 -4
  72. wagtail/admin/templates/wagtailadmin/pages/create.html +15 -34
  73. wagtail/admin/templates/wagtailadmin/pages/edit.html +15 -30
  74. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +6 -0
  75. wagtail/admin/templates/wagtailadmin/pages/explorable_index_results.html +60 -0
  76. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -36
  77. wagtail/admin/templates/wagtailadmin/pages/index_results.html +2 -50
  78. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/pages/listing/_ordering_cell.html +1 -1
  80. wagtail/admin/templates/wagtailadmin/pages/listing/_page_header_buttons.html +1 -1
  81. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +3 -3
  82. wagtail/admin/templates/wagtailadmin/pages/listing/_pagination.html +1 -1
  83. wagtail/admin/templates/wagtailadmin/pages/listing.html +24 -0
  84. wagtail/admin/templates/wagtailadmin/pages/search.html +1 -20
  85. wagtail/admin/templates/wagtailadmin/pages/search_results.html +27 -25
  86. wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_formset.html +0 -1
  87. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_report.html +2 -2
  88. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_types_usage.html +6 -6
  89. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks_results.html +1 -1
  90. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu.html +14 -0
  91. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu_item.html +6 -0
  92. wagtail/admin/templates/wagtailadmin/shared/avatar.html +13 -3
  93. wagtail/admin/templates/wagtailadmin/shared/header.html +0 -5
  94. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +1 -1
  95. wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +4 -1
  96. wagtail/admin/templates/wagtailadmin/shared/pagination_nav.html +1 -1
  97. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +1 -1
  98. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/locale.html +1 -1
  99. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/usage.html +2 -2
  100. wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +94 -52
  101. wagtail/admin/templates/wagtailadmin/{pages/_unsaved_changes_warning.html → shared/unsaved_changes_warning.html} +4 -4
  102. wagtail/admin/templates/wagtailadmin/shared/usage_summary.html +2 -2
  103. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +1 -7
  104. wagtail/admin/templates/wagtailadmin/shared/workflow_history/listing.html +1 -0
  105. wagtail/admin/templates/wagtailadmin/shared/workflow_history/{list.html → listing_results.html} +33 -35
  106. wagtail/admin/templates/wagtailadmin/tables/references_cell.html +1 -1
  107. wagtail/admin/templates/wagtailadmin/workflows/create.html +11 -36
  108. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +0 -38
  109. wagtail/admin/templates/wagtailadmin/workflows/edit.html +44 -74
  110. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +27 -66
  111. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -2
  112. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +4 -4
  113. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +15 -11
  114. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/includes/results.html +7 -5
  115. wagtail/admin/templatetags/wagtailadmin_tags.py +51 -22
  116. wagtail/admin/tests/pages/test_content_type_use_view.py +82 -2
  117. wagtail/admin/tests/pages/test_edit_page.py +70 -0
  118. wagtail/admin/tests/pages/test_explorer_view.py +65 -4
  119. wagtail/admin/tests/pages/test_page_search.py +8 -7
  120. wagtail/admin/tests/pages/test_page_usage.py +3 -1
  121. wagtail/admin/tests/pages/test_preview.py +208 -63
  122. wagtail/admin/tests/pages/test_reorder_page.py +91 -1
  123. wagtail/admin/tests/pages/test_view_draft.py +32 -1
  124. wagtail/admin/tests/pages/test_workflow_history.py +288 -7
  125. wagtail/admin/tests/test_account_management.py +23 -3
  126. wagtail/admin/tests/test_audit_log.py +24 -2
  127. wagtail/admin/tests/test_collections_views.py +17 -5
  128. wagtail/admin/tests/test_dashboard.py +1 -1
  129. wagtail/admin/tests/test_edit_handlers.py +3 -2
  130. wagtail/admin/tests/test_icon_sprite.py +4 -0
  131. wagtail/admin/tests/test_privacy.py +5 -19
  132. wagtail/admin/tests/test_reports_views.py +1 -1
  133. wagtail/admin/tests/test_site_summary.py +3 -3
  134. wagtail/admin/tests/test_templatetags.py +27 -3
  135. wagtail/admin/tests/test_upgrade_notification.py +71 -18
  136. wagtail/admin/tests/test_views.py +2 -2
  137. wagtail/admin/tests/test_views_generic.py +13 -0
  138. wagtail/admin/tests/test_widgets.py +3 -3
  139. wagtail/admin/tests/test_workflows.py +172 -27
  140. wagtail/admin/tests/tests.py +1 -1
  141. wagtail/admin/tests/viewsets/test_model_viewset.py +55 -3
  142. wagtail/admin/ui/side_panels.py +19 -0
  143. wagtail/admin/ui/sidebar.py +4 -3
  144. wagtail/admin/ui/tables/__init__.py +14 -1
  145. wagtail/admin/ui/tables/pages.py +6 -1
  146. wagtail/admin/urls/pages.py +10 -1
  147. wagtail/admin/urls/workflows.py +6 -1
  148. wagtail/admin/views/account.py +5 -1
  149. wagtail/admin/views/collections.py +0 -2
  150. wagtail/admin/views/generic/base.py +118 -1
  151. wagtail/admin/views/generic/history.py +158 -26
  152. wagtail/admin/views/generic/models.py +113 -99
  153. wagtail/admin/views/home.py +24 -9
  154. wagtail/admin/views/page_privacy.py +54 -30
  155. wagtail/admin/views/pages/history.py +11 -4
  156. wagtail/admin/views/pages/listing.py +76 -89
  157. wagtail/admin/views/pages/preview.py +1 -1
  158. wagtail/admin/views/pages/search.py +27 -71
  159. wagtail/admin/views/pages/usage.py +63 -24
  160. wagtail/admin/views/pages/utils.py +4 -3
  161. wagtail/admin/views/reports/base.py +0 -6
  162. wagtail/admin/views/workflows.py +67 -25
  163. wagtail/admin/viewsets/model.py +4 -3
  164. wagtail/admin/widgets/chooser.py +2 -1
  165. wagtail/api/v2/tests/test_pages.py +15 -2
  166. wagtail/blocks/field_block.py +15 -3
  167. wagtail/blocks/static_block.py +3 -0
  168. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.mo +0 -0
  169. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.po +29 -1
  170. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +15 -11
  171. wagtail/contrib/forms/templates/wagtailforms/confirm_delete.html +1 -0
  172. wagtail/contrib/forms/templates/wagtailforms/index.html +1 -1
  173. wagtail/contrib/forms/templates/wagtailforms/index_results.html +1 -1
  174. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +2 -1
  175. wagtail/contrib/forms/templates/wagtailforms/panels/form_responses_panel.html +2 -2
  176. wagtail/contrib/forms/tests/test_views.py +234 -35
  177. wagtail/contrib/forms/utils.py +8 -14
  178. wagtail/contrib/forms/views.py +72 -27
  179. wagtail/contrib/frontend_cache/backends/azure.py +1 -1
  180. wagtail/contrib/frontend_cache/backends/cloudfront.py +2 -2
  181. wagtail/contrib/frontend_cache/backends/dummy.py +11 -0
  182. wagtail/contrib/frontend_cache/tests.py +31 -37
  183. wagtail/contrib/frontend_cache/utils.py +12 -5
  184. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.mo +0 -0
  185. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.po +16 -1
  186. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +20 -24
  187. wagtail/contrib/redirects/models.py +16 -1
  188. wagtail/contrib/redirects/signal_handlers.py +18 -3
  189. wagtail/contrib/redirects/templates/wagtailredirects/add.html +5 -16
  190. wagtail/contrib/redirects/templates/wagtailredirects/import_summary.html +1 -1
  191. wagtail/contrib/redirects/tests/test_redirects.py +49 -6
  192. wagtail/contrib/redirects/tests/test_signal_handlers.py +42 -1
  193. wagtail/contrib/redirects/views.py +27 -3
  194. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.mo +0 -0
  195. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.po +60 -1
  196. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +12 -18
  197. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/add.html +5 -8
  198. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/edit.html +15 -10
  199. wagtail/contrib/search_promotions/tests.py +13 -2
  200. wagtail/contrib/search_promotions/views.py +15 -3
  201. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.mo +0 -0
  202. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.po +6 -1
  203. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +2 -10
  204. wagtail/contrib/settings/templates/wagtailsettings/edit.html +12 -45
  205. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.mo +0 -0
  206. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.po +13 -1
  207. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.mo +0 -0
  208. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.po +3 -0
  209. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +4 -4
  210. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.mo +0 -0
  211. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.po +5 -2
  212. wagtail/contrib/simple_translation/tests/test_views.py +51 -0
  213. wagtail/contrib/simple_translation/wagtail_hooks.py +16 -11
  214. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.mo +0 -0
  215. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.po +5 -1
  216. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  217. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  218. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.po +27 -1
  219. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  220. wagtail/contrib/typed_table_block/blocks.py +25 -0
  221. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  222. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.po +12 -1
  223. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  224. wagtail/contrib/typed_table_block/tests.py +24 -1
  225. wagtail/coreutils.py +5 -11
  226. wagtail/documents/admin_urls.py +2 -2
  227. wagtail/documents/locale/cy/LC_MESSAGES/django.mo +0 -0
  228. wagtail/documents/locale/cy/LC_MESSAGES/django.po +10 -0
  229. wagtail/documents/locale/en/LC_MESSAGES/django.po +61 -76
  230. wagtail/documents/migrations/0014_alter_document_file_size.py +18 -0
  231. wagtail/documents/models.py +1 -1
  232. wagtail/documents/rich_text/__init__.py +1 -3
  233. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  234. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_tags.html +5 -1
  235. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  236. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_delete.html +11 -5
  237. wagtail/documents/templates/wagtaildocs/documents/add.html +13 -41
  238. wagtail/documents/templates/wagtaildocs/documents/edit.html +28 -56
  239. wagtail/documents/templates/wagtaildocs/documents/index.html +1 -4
  240. wagtail/documents/templates/wagtaildocs/homepage/site_summary_documents.html +2 -2
  241. wagtail/documents/templates/wagtaildocs/multiple/add.html +36 -41
  242. wagtail/documents/tests/test_admin_views.py +64 -6
  243. wagtail/documents/tests/test_site_summary.py +3 -3
  244. wagtail/documents/views/documents.py +103 -113
  245. wagtail/documents/views/multiple.py +19 -1
  246. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  247. wagtail/embeds/oembed_providers.py +9 -19
  248. wagtail/fields.py +43 -27
  249. wagtail/images/admin_urls.py +2 -2
  250. wagtail/images/blocks.py +230 -2
  251. wagtail/images/fields.py +17 -29
  252. wagtail/images/image_operations.py +1 -1
  253. wagtail/images/locale/cy/LC_MESSAGES/django.mo +0 -0
  254. wagtail/images/locale/cy/LC_MESSAGES/django.po +128 -1
  255. wagtail/images/locale/en/LC_MESSAGES/django.po +119 -129
  256. wagtail/images/migrations/0025_alter_image_file_alter_rendition_file.py +36 -43
  257. wagtail/images/migrations/0027_image_description.py +20 -0
  258. wagtail/images/models.py +120 -45
  259. wagtail/images/rich_text/__init__.py +1 -3
  260. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  261. wagtail/images/static/wagtailimages/js/image-block.js +1 -0
  262. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_tags.html +5 -1
  263. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  264. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_delete.html +11 -5
  265. wagtail/images/templates/wagtailimages/chooser/results.html +2 -2
  266. wagtail/images/templates/wagtailimages/homepage/site_summary_images.html +2 -2
  267. wagtail/images/templates/wagtailimages/images/_file_field.html +2 -2
  268. wagtail/images/templates/wagtailimages/images/add.html +13 -31
  269. wagtail/images/templates/wagtailimages/images/edit.html +53 -82
  270. wagtail/images/templates/wagtailimages/images/index.html +1 -4
  271. wagtail/images/templates/wagtailimages/images/url_generator.html +1 -1
  272. wagtail/images/templates/wagtailimages/multiple/add.html +40 -47
  273. wagtail/images/templates/wagtailimages/widgets/image.html +5 -0
  274. wagtail/images/templates/wagtailimages/widgets/image_chooser.html +1 -1
  275. wagtail/images/tests/test_admin_views.py +70 -10
  276. wagtail/images/tests/test_blocks.py +367 -1
  277. wagtail/images/tests/test_image_operations.py +23 -0
  278. wagtail/images/tests/test_models.py +20 -0
  279. wagtail/images/tests/test_signal_handlers.py +99 -95
  280. wagtail/images/tests/test_site_summary.py +3 -3
  281. wagtail/images/tests/test_templatetags.py +11 -7
  282. wagtail/images/tests/tests.py +4 -0
  283. wagtail/images/views/images.py +103 -104
  284. wagtail/images/views/multiple.py +17 -1
  285. wagtail/locale/cy/LC_MESSAGES/django.mo +0 -0
  286. wagtail/locale/cy/LC_MESSAGES/django.po +3 -0
  287. wagtail/locale/en/LC_MESSAGES/django.po +137 -125
  288. wagtail/locale/sl/LC_MESSAGES/django.mo +0 -0
  289. wagtail/locale/sl/LC_MESSAGES/django.po +3 -0
  290. wagtail/locales/locale/en/LC_MESSAGES/django.po +8 -8
  291. wagtail/locales/views.py +4 -1
  292. wagtail/migrations/0089_log_entry_data_json_null_to_object.py +1 -7
  293. wagtail/models/__init__.py +122 -14
  294. wagtail/models/audit_log.py +1 -3
  295. wagtail/models/i18n.py +1 -2
  296. wagtail/project_template/Dockerfile +3 -3
  297. wagtail/project_template/requirements.txt +2 -2
  298. wagtail/query.py +17 -4
  299. wagtail/rich_text/__init__.py +2 -3
  300. wagtail/rich_text/pages.py +2 -4
  301. wagtail/rich_text/rewriters.py +2 -2
  302. wagtail/search/backends/database/mysql/query.py +3 -3
  303. wagtail/search/backends/database/sqlite/query.py +6 -6
  304. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  305. wagtail/sites/locale/en/LC_MESSAGES/django.po +6 -6
  306. wagtail/sites/views.py +0 -1
  307. wagtail/snippets/action_menu.py +14 -4
  308. wagtail/snippets/locale/cy/LC_MESSAGES/django.mo +0 -0
  309. wagtail/snippets/locale/cy/LC_MESSAGES/django.po +73 -1
  310. wagtail/snippets/locale/en/LC_MESSAGES/django.po +27 -33
  311. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  312. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  313. wagtail/snippets/templates/wagtailsnippets/bulk_actions/confirm_bulk_delete.html +5 -3
  314. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/locked.html +1 -1
  315. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu.html +1 -11
  316. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu_item.html +1 -6
  317. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +1 -1
  318. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +1 -1
  319. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -18
  320. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -14
  321. wagtail/snippets/templates/wagtailsnippets/snippets/index.html +2 -5
  322. wagtail/snippets/tests/test_preview.py +193 -61
  323. wagtail/snippets/tests/test_snippets.py +247 -38
  324. wagtail/snippets/tests/test_usage.py +5 -0
  325. wagtail/snippets/tests/test_viewset.py +25 -9
  326. wagtail/snippets/tests/test_workflows.py +232 -19
  327. wagtail/snippets/views/snippets.py +1 -10
  328. wagtail/test/numberformat.py +104 -0
  329. wagtail/test/settings.py +10 -0
  330. wagtail/test/settings_ui.py +2 -0
  331. wagtail/test/testapp/migrations/0010_alter_customimage_file_and_more.py +71 -78
  332. wagtail/test/testapp/migrations/0040_nocreatablesubpagetypespage_nosubpagetypespage.py +54 -0
  333. wagtail/test/testapp/migrations/0041_alter_jsonstreammodel_options.py +17 -0
  334. wagtail/test/testapp/migrations/0042_alter_customdocument_file_size_and_more.py +28 -0
  335. wagtail/test/testapp/migrations/0043_customimage_description.py +41 -0
  336. wagtail/test/testapp/migrations/0044_custompreviewsizesmodel_custompreviewsizespage.py +52 -0
  337. wagtail/test/testapp/migrations/0045_alter_streampage_body.py +52 -0
  338. wagtail/test/testapp/models.py +62 -4
  339. wagtail/test/testapp/rich_text.py +2 -2
  340. wagtail/test/testapp/templates/tests/form_page_landing.html +2 -1
  341. wagtail/test/testapp/urls.py +5 -0
  342. wagtail/test/testapp/views.py +5 -0
  343. wagtail/test/utils/page_tests.py +5 -5
  344. wagtail/test/utils/template_tests.py +2 -2
  345. wagtail/tests/test_blocks.py +15 -0
  346. wagtail/tests/test_page_permissions.py +109 -0
  347. wagtail/tests/test_revision_model.py +27 -0
  348. wagtail/tests/test_signals.py +21 -2
  349. wagtail/tests/test_tests.py +30 -0
  350. wagtail/users/locale/cy/LC_MESSAGES/django.mo +0 -0
  351. wagtail/users/locale/cy/LC_MESSAGES/django.po +118 -1
  352. wagtail/users/locale/dv/LC_MESSAGES/django.mo +0 -0
  353. wagtail/users/locale/dv/LC_MESSAGES/django.po +3 -0
  354. wagtail/users/locale/en/LC_MESSAGES/django.po +89 -113
  355. wagtail/users/locale/sl/LC_MESSAGES/django.mo +0 -0
  356. wagtail/users/locale/sl/LC_MESSAGES/django.po +3 -0
  357. wagtail/users/migrations/0014_userprofile_contrast.py +23 -0
  358. wagtail/users/models.py +11 -0
  359. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_assign_role.html +5 -1
  360. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_delete.html +5 -1
  361. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_set_active_state.html +5 -1
  362. wagtail/users/templates/wagtailusers/groups/create.html +19 -17
  363. wagtail/users/templates/wagtailusers/groups/edit.html +2 -40
  364. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +1 -62
  365. wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.html +0 -1
  366. wagtail/users/templates/wagtailusers/users/create.html +46 -50
  367. wagtail/users/templates/wagtailusers/users/edit.html +45 -62
  368. wagtail/users/templates/wagtailusers/users/index.html +1 -4
  369. wagtail/users/templatetags/wagtailusers_tags.py +1 -5
  370. wagtail/users/tests/test_admin_views.py +85 -66
  371. wagtail/users/views/groups.py +4 -1
  372. wagtail/users/views/users.py +2 -0
  373. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/METADATA +6 -6
  374. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/RECORD +378 -367
  375. wagtail/admin/static/wagtailadmin/js/preview-panel.js +0 -2
  376. wagtail/admin/static/wagtailadmin/js/preview-panel.js.LICENSE.txt +0 -11
  377. wagtail/admin/templates/wagtailadmin/generic/history_results.html +0 -1
  378. wagtail/admin/templates/wagtailadmin/page_privacy/ancestor_privacy.html +0 -3
  379. wagtail/admin/templates/wagtailadmin/pages/usage_results.html +0 -6
  380. wagtail/admin/templates/wagtailadmin/shared/workflow_history/index.html +0 -17
  381. wagtail/admin/templates/wagtailadmin/shared/workflow_history/results.html +0 -17
  382. wagtail/admin/templates/wagtailadmin/workflows/usage.html +0 -44
  383. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/LICENSE +0 -0
  384. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/WHEEL +0 -0
  385. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/entry_points.txt +0 -0
  386. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,7 @@ msgid ""
8
8
  msgstr ""
9
9
  "Project-Id-Version: PACKAGE VERSION\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2024-08-07 10:06+0100\n"
11
+ "POT-Creation-Date: 2024-10-21 17:53+0100\n"
12
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -148,7 +148,7 @@ msgstr ""
148
148
  msgid "help text"
149
149
  msgstr ""
150
150
 
151
- #: models.py:195 views.py:149
151
+ #: models.py:195 views.py:194
152
152
  msgid "Submission date"
153
153
  msgstr ""
154
154
 
@@ -198,15 +198,15 @@ msgid_plural "Are you sure you want to delete these form submissions?"
198
198
  msgstr[0] ""
199
199
  msgstr[1] ""
200
200
 
201
- #: templates/wagtailforms/confirm_delete.html:20
201
+ #: templates/wagtailforms/confirm_delete.html:21
202
202
  msgid "Delete"
203
203
  msgstr ""
204
204
 
205
- #: templates/wagtailforms/list_submissions.html:36
205
+ #: templates/wagtailforms/list_submissions.html:37
206
206
  msgid "Delete selected submissions"
207
207
  msgstr ""
208
208
 
209
- #: templates/wagtailforms/list_submissions.html:44
209
+ #: templates/wagtailforms/list_submissions.html:45
210
210
  #, python-format
211
211
  msgid "There have been no submissions of the '%(title)s' form."
212
212
  msgstr ""
@@ -224,29 +224,33 @@ msgstr ""
224
224
  msgid "Submissions of %(form_title)s"
225
225
  msgstr ""
226
226
 
227
- #: views.py:52 views.py:267 wagtail_hooks.py:26
227
+ #: views.py:54
228
+ msgid "Page type"
229
+ msgstr ""
230
+
231
+ #: views.py:81 views.py:311 wagtail_hooks.py:26
228
232
  msgid "Forms"
229
233
  msgstr ""
230
234
 
231
- #: views.py:59
235
+ #: views.py:97
232
236
  msgid "Title"
233
237
  msgstr ""
234
238
 
235
- #: views.py:66
239
+ #: views.py:107
236
240
  msgid "Origin"
237
241
  msgstr ""
238
242
 
239
- #: views.py:76
243
+ #: views.py:116
240
244
  msgid "Pages"
241
245
  msgstr ""
242
246
 
243
- #: views.py:105
247
+ #: views.py:146
244
248
  #, python-format
245
249
  msgid "One submission has been deleted."
246
250
  msgid_plural "%(count)d submissions have been deleted."
247
251
  msgstr[0] ""
248
252
  msgstr[1] ""
249
253
 
250
- #: views.py:168
254
+ #: views.py:213
251
255
  msgid "Form data"
252
256
  msgstr ""
@@ -17,6 +17,7 @@
17
17
  </p>
18
18
  <form action="{% url 'wagtailforms:delete_submissions' page.id %}?{{ request.GET.urlencode }}" method="POST">
19
19
  {% csrf_token %}
20
+ <input type="hidden" value="{{ next_url }}" name="next">
20
21
  <input type="submit" value="{% trans 'Delete' %}" class="button serious">
21
22
  </form>
22
23
  </div>
@@ -1 +1 @@
1
- {% extends "wagtailadmin/generic/index.html" %}
1
+ {% extends "wagtailadmin/pages/listing.html" %}
@@ -1 +1 @@
1
- {% extends "wagtailadmin/generic/index_results.html" %}
1
+ {% extends "wagtailadmin/generic/listing_results.html" %}
@@ -1,7 +1,8 @@
1
- {% extends "wagtailadmin/generic/index_results.html" %}
1
+ {% extends "wagtailadmin/generic/listing_results.html" %}
2
2
  {% load i18n l10n %}
3
3
  {% block results %}
4
4
  <form class="w-overflow-auto" data-controller="w-bulk" data-w-bulk-action-inactive-class="w-invisible" action="{% url 'wagtailforms:delete_submissions' form_page.id %}" method="get">
5
+ <input type="hidden" value="{{ next_url }}" name="next">
5
6
  <table class="listing">
6
7
  <col />
7
8
  <col />
@@ -1,8 +1,8 @@
1
- {% load i18n %}
1
+ {% load i18n wagtailadmin_tags %}
2
2
  {% trans "Total submissions" as total %}
3
3
  {% trans "Latest submission" as latest %}
4
4
  <p>
5
- <span class="w-label-3">{{ total }}</span> <a href="{% url 'wagtailforms:list_submissions' self.instance.id %}">{{ submission_count }}</a>
5
+ <span class="w-label-3">{{ total }}</span> <a href="{% url 'wagtailforms:list_submissions' self.instance.id %}">{{ submission_count|intcomma }}</a>
6
6
  </p>
7
7
  <p>
8
8
  <span class="w-label-3">{{ latest }}</span> {{ last_submit_time }}
@@ -3,6 +3,7 @@ from io import BytesIO
3
3
 
4
4
  from django.conf import settings
5
5
  from django.contrib.auth.models import AnonymousUser
6
+ from django.contrib.contenttypes.models import ContentType
6
7
  from django.test import RequestFactory, TestCase, override_settings
7
8
  from django.urls import reverse
8
9
  from django.utils.html import escape
@@ -17,7 +18,9 @@ from wagtail.contrib.forms.tests.utils import (
17
18
  make_form_page,
18
19
  make_form_page_with_custom_submission,
19
20
  )
21
+ from wagtail.contrib.forms.utils import get_form_types
20
22
  from wagtail.models import Locale, Page
23
+ from wagtail.test.demosite.models import FormPage as FormPageDemo
21
24
  from wagtail.test.testapp.models import (
22
25
  CustomFormPageSubmission,
23
26
  ExtendedFormField,
@@ -28,6 +31,8 @@ from wagtail.test.testapp.models import (
28
31
  FormPageWithCustomFormBuilder,
29
32
  FormPageWithCustomSubmission,
30
33
  FormPageWithCustomSubmissionListView,
34
+ FormPageWithRedirect,
35
+ JadeFormPage,
31
36
  )
32
37
  from wagtail.test.utils import WagtailTestUtils
33
38
  from wagtail.test.utils.form_data import inline_formset, nested_form_data
@@ -154,16 +159,35 @@ class TestFormsIndex(WagtailTestUtils, TestCase):
154
159
 
155
160
  def setUp(self):
156
161
  self.login(username="siteeditor", password="password")
157
- self.form_page = Page.objects.get(url_path="/home/contact-us/")
162
+ get_form_types.cache_clear()
163
+
164
+ @classmethod
165
+ def setUpTestData(cls):
166
+ cls.form_page = Page.objects.specific().get(url_path="/home/contact-us/")
167
+ # Save a revision so latest_revision_created_at is populated, and thus
168
+ # the form page is always shown first when using the default ordering
169
+ # (latest_revision_created_at descending).
170
+ cls.form_page.save_revision()
171
+ cls.models = [
172
+ FormPage,
173
+ FormPageWithRedirect,
174
+ FormPageWithCustomFormBuilder,
175
+ FormPageWithCustomSubmission,
176
+ FormPageWithCustomSubmissionListView,
177
+ JadeFormPage,
178
+ FormPageDemo,
179
+ ]
180
+ cls.make_form_pages()
158
181
 
159
- def make_form_pages(self):
182
+ @classmethod
183
+ def make_form_pages(cls):
160
184
  """
161
185
  This makes 100 form pages and adds them as children to 'contact-us'
162
186
  This is used to test pagination on the forms index
163
187
  """
164
188
  for i in range(100):
165
- self.form_page.add_child(
166
- instance=FormPage(
189
+ cls.form_page.add_child(
190
+ instance=cls.models[i % len(cls.models)](
167
191
  title="Form " + str(i), slug="form-" + str(i), live=True
168
192
  )
169
193
  )
@@ -176,9 +200,6 @@ class TestFormsIndex(WagtailTestUtils, TestCase):
176
200
  self.assertTemplateUsed(response, "wagtailforms/index.html")
177
201
 
178
202
  def test_forms_index_pagination(self):
179
- # Create some more form pages to make pagination kick in
180
- self.make_form_pages()
181
-
182
203
  # Get page two
183
204
  response = self.client.get(reverse("wagtailforms:index"), {"p": 2})
184
205
 
@@ -190,39 +211,51 @@ class TestFormsIndex(WagtailTestUtils, TestCase):
190
211
  self.assertEqual(response.context["page_obj"].number, 2)
191
212
 
192
213
  def test_forms_index_pagination_invalid(self):
193
- # Create some more form pages to make pagination kick in
194
- self.make_form_pages()
195
-
196
214
  # Get page two
197
215
  response = self.client.get(reverse("wagtailforms:index"), {"p": "Hello world!"})
198
216
 
199
217
  # Check response
200
- self.assertEqual(response.status_code, 404)
218
+ self.assertEqual(response.status_code, 200)
219
+ self.assertTemplateUsed(response, "wagtailforms/index.html")
201
220
 
202
- def test_forms_index_pagination_out_of_range(self):
203
- # Create some more form pages to make pagination kick in
204
- self.make_form_pages()
221
+ # Check that it got page one
222
+ self.assertEqual(response.context["page_obj"].number, 1)
205
223
 
206
- # Get page two
224
+ def test_forms_index_pagination_out_of_range(self):
225
+ # Get page that is out of range
207
226
  response = self.client.get(reverse("wagtailforms:index"), {"p": 99999})
208
227
 
209
228
  # Check response
210
- self.assertEqual(response.status_code, 404)
229
+ self.assertEqual(response.status_code, 200)
230
+ self.assertTemplateUsed(response, "wagtailforms/index.html")
231
+
232
+ # Check that it got the last page
233
+ self.assertEqual(
234
+ response.context["page_obj"].number, response.context["paginator"].num_pages
235
+ )
211
236
 
212
237
  def test_cannot_see_forms_without_permission(self):
238
+ self.login(username="admin_only_user", password="password")
239
+ response = self.client.get(reverse("wagtailforms:index"))
240
+ self.assertRedirects(response, reverse("wagtailadmin_home"))
241
+
213
242
  # Login with as a user without permission to see forms
214
243
  self.login(username="eventeditor", password="password")
215
244
 
216
245
  response = self.client.get(reverse("wagtailforms:index"))
246
+ self.assertEqual(response.status_code, 200)
217
247
 
218
248
  # Check that the user cannot see the form page
219
249
  self.assertNotIn(self.form_page, response.context["form_pages"])
250
+ self.assertEqual(len(response.context["form_pages"]), 0)
220
251
 
221
252
  def test_can_see_forms_with_permission(self):
222
253
  response = self.client.get(reverse("wagtailforms:index"))
254
+ self.assertEqual(response.status_code, 200)
223
255
 
224
256
  # Check that the user can see the form page
225
257
  self.assertIn(self.form_page, response.context["form_pages"])
258
+ self.assertEqual(len(response.context["form_pages"]), 20)
226
259
 
227
260
  def test_cant_see_forms_after_filter_form_submissions_for_user_hook(self):
228
261
  # Hook allows to see forms only to superusers
@@ -236,6 +269,7 @@ class TestFormsIndex(WagtailTestUtils, TestCase):
236
269
 
237
270
  # Check that an user can see the form page
238
271
  self.assertIn(self.form_page, response.context["form_pages"])
272
+ self.assertEqual(len(response.context["form_pages"]), 20)
239
273
 
240
274
  with self.register_hook(
241
275
  "filter_form_submissions_for_user", construct_forms_for_user
@@ -244,6 +278,65 @@ class TestFormsIndex(WagtailTestUtils, TestCase):
244
278
 
245
279
  # Check that an user can't see the form page
246
280
  self.assertNotIn(self.form_page, response.context["form_pages"])
281
+ self.assertEqual(len(response.context["form_pages"]), 0)
282
+
283
+ def test_search(self):
284
+ response = self.client.get(reverse("wagtailforms:index"), {"q": "Form 10"})
285
+
286
+ self.assertNotIn(self.form_page, response.context["form_pages"])
287
+ self.assertCountEqual(
288
+ [page.title for page in response.context["form_pages"]],
289
+ ["Form 10"],
290
+ )
291
+
292
+ def test_filter_by_page_type(self):
293
+ content_type_ids = [
294
+ ct.pk
295
+ for ct in ContentType.objects.get_for_models(
296
+ FormPageWithRedirect, FormPageDemo
297
+ ).values()
298
+ ]
299
+ response = self.client.get(
300
+ reverse("wagtailforms:index"),
301
+ {"content_type": content_type_ids},
302
+ )
303
+
304
+ soup = self.get_soup(response.content)
305
+ inputs = soup.select('input[name="content_type"]')
306
+ self.assertCountEqual(
307
+ [int(input.attrs.get("value")) for input in inputs],
308
+ [ct.pk for ct in ContentType.objects.get_for_models(*self.models).values()],
309
+ )
310
+ selected_cts = soup.select('input[name="content_type"][checked]')
311
+ self.assertEqual(len(selected_cts), 2)
312
+ self.assertCountEqual(
313
+ [int(input.attrs.get("value")) for input in selected_cts],
314
+ content_type_ids,
315
+ )
316
+
317
+ # Check that only pages of the selected types are shown
318
+ self.assertNotIn(self.form_page, response.context["form_pages"])
319
+ self.assertEqual(
320
+ {page.__class__ for page in response.context["form_pages"]},
321
+ {FormPageWithRedirect, FormPageDemo},
322
+ )
323
+
324
+ def test_search_and_filter(self):
325
+ response = self.client.get(
326
+ reverse("wagtailforms:index"),
327
+ {
328
+ "q": "Contact",
329
+ "content_type": ContentType.objects.get_for_model(FormPage).pk,
330
+ },
331
+ )
332
+
333
+ self.assertIn(self.form_page, response.context["form_pages"])
334
+ # The "Contact us one more time" page from the fixtures is not included
335
+ # because it's a FormPageWithCustomSubmission, not a FormPage
336
+ self.assertCountEqual(
337
+ [page.title for page in response.context["form_pages"]],
338
+ ["Contact us"],
339
+ )
247
340
 
248
341
 
249
342
  @override_settings(WAGTAIL_I18N_ENABLED=True)
@@ -319,7 +412,15 @@ class TestFormsIndexWithLocalisationEnabled(WagtailTestUtils, TestCase):
319
412
  self.assertEqual(len(response.context["page_obj"].object_list), 3)
320
413
 
321
414
  response = self.client.get(self.forms_index_url, {"p": 4})
322
- self.assertEqual(response.status_code, 404)
415
+ # Check response
416
+ self.assertEqual(response.status_code, 200)
417
+ self.assertTemplateUsed(response, "wagtailforms/index.html")
418
+
419
+ # Check that we got the last page
420
+ self.assertEqual(
421
+ response.context["page_obj"].number,
422
+ response.context["paginator"].num_pages,
423
+ )
323
424
 
324
425
  # now check the French pages.
325
426
  response = self.client.get(
@@ -331,8 +432,9 @@ class TestFormsIndexWithLocalisationEnabled(WagtailTestUtils, TestCase):
331
432
  @override_settings(WAGTAIL_I18N_ENABLED=False)
332
433
  def test_switcher_doesnt_show_with_i18n_disabled(self):
333
434
  response = self.client.get(self.forms_index_url)
334
-
335
- self.assertNotContains(response, "data-locale-selector")
435
+ soup = self.get_soup(response.content)
436
+ inputs = soup.select('input[name="locale"]')
437
+ self.assertEqual(len(inputs), 0)
336
438
 
337
439
 
338
440
  class TestFormsSubmissionsList(WagtailTestUtils, TestCase):
@@ -463,10 +565,8 @@ class TestFormsSubmissionsList(WagtailTestUtils, TestCase):
463
565
  def test_list_submissions_pagination(self):
464
566
  self.make_list_submissions()
465
567
 
466
- response = self.client.get(
467
- reverse("wagtailforms:list_submissions", args=(self.form_page.id,)),
468
- {"p": 2},
469
- )
568
+ list_url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,))
569
+ response = self.client.get(list_url, {"p": 2})
470
570
 
471
571
  # Check response
472
572
  self.assertEqual(response.status_code, 200)
@@ -475,6 +575,18 @@ class TestFormsSubmissionsList(WagtailTestUtils, TestCase):
475
575
  # Check that we got the correct page
476
576
  self.assertEqual(response.context["page_obj"].number, 2)
477
577
 
578
+ # The delete form should have a 'next' input that points back to the list page
579
+ # with the same pagination querystring
580
+ soup = self.get_soup(response.content)
581
+ delete_url = reverse(
582
+ "wagtailforms:delete_submissions", args=(self.form_page.id,)
583
+ )
584
+ form = soup.find("form", {"action": delete_url})
585
+ self.assertIsNotNone(form)
586
+ next_input = form.find("input", {"name": "next"})
587
+ self.assertIsNotNone(next_input)
588
+ self.assertEqual(next_input.get("value"), f"{list_url}?p=2")
589
+
478
590
  def test_list_submissions_pagination_invalid(self):
479
591
  self.make_list_submissions()
480
592
 
@@ -484,7 +596,11 @@ class TestFormsSubmissionsList(WagtailTestUtils, TestCase):
484
596
  )
485
597
 
486
598
  # Check response
487
- self.assertEqual(response.status_code, 404)
599
+ self.assertEqual(response.status_code, 200)
600
+ self.assertTemplateUsed(response, "wagtailforms/submissions_index.html")
601
+
602
+ # Check that we got page one
603
+ self.assertEqual(response.context["page_obj"].number, 1)
488
604
 
489
605
  def test_list_submissions_pagination_out_of_range(self):
490
606
  self.make_list_submissions()
@@ -495,7 +611,13 @@ class TestFormsSubmissionsList(WagtailTestUtils, TestCase):
495
611
  )
496
612
 
497
613
  # Check response
498
- self.assertEqual(response.status_code, 404)
614
+ self.assertEqual(response.status_code, 200)
615
+ self.assertTemplateUsed(response, "wagtailforms/submissions_index.html")
616
+
617
+ # Check that we got the last page
618
+ self.assertEqual(
619
+ response.context["page_obj"].number, response.context["paginator"].num_pages
620
+ )
499
621
 
500
622
  def test_list_submissions_default_order(self):
501
623
  response = self.client.get(
@@ -1156,10 +1278,8 @@ class TestCustomFormsSubmissionsList(WagtailTestUtils, TestCase):
1156
1278
  def test_list_submissions_pagination(self):
1157
1279
  self.make_list_submissions()
1158
1280
 
1159
- response = self.client.get(
1160
- reverse("wagtailforms:list_submissions", args=(self.form_page.id,)),
1161
- {"p": 2},
1162
- )
1281
+ list_url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,))
1282
+ response = self.client.get(list_url, {"p": 2})
1163
1283
 
1164
1284
  # Check response
1165
1285
  self.assertEqual(response.status_code, 200)
@@ -1174,6 +1294,18 @@ class TestCustomFormsSubmissionsList(WagtailTestUtils, TestCase):
1174
1294
  )
1175
1295
  self.assertContains(response, "generated-username-", count=20)
1176
1296
 
1297
+ # The delete form should have a 'next' input that points back to the list page
1298
+ # with the same pagination querystring
1299
+ soup = self.get_soup(response.content)
1300
+ delete_url = reverse(
1301
+ "wagtailforms:delete_submissions", args=(self.form_page.id,)
1302
+ )
1303
+ form = soup.find("form", {"action": delete_url})
1304
+ self.assertIsNotNone(form)
1305
+ next_input = form.find("input", {"name": "next"})
1306
+ self.assertIsNotNone(next_input)
1307
+ self.assertEqual(next_input.get("value"), f"{list_url}?p=2")
1308
+
1177
1309
  def test_list_submissions_pagination_invalid(self):
1178
1310
  self.make_list_submissions()
1179
1311
 
@@ -1183,7 +1315,11 @@ class TestCustomFormsSubmissionsList(WagtailTestUtils, TestCase):
1183
1315
  )
1184
1316
 
1185
1317
  # Check response
1186
- self.assertEqual(response.status_code, 404)
1318
+ self.assertEqual(response.status_code, 200)
1319
+ self.assertTemplateUsed(response, "wagtailforms/submissions_index.html")
1320
+
1321
+ # Check that we got page one
1322
+ self.assertEqual(response.context["page_obj"].number, 1)
1187
1323
 
1188
1324
  def test_list_submissions_pagination_out_of_range(self):
1189
1325
  self.make_list_submissions()
@@ -1194,7 +1330,13 @@ class TestCustomFormsSubmissionsList(WagtailTestUtils, TestCase):
1194
1330
  )
1195
1331
 
1196
1332
  # Check response
1197
- self.assertEqual(response.status_code, 404)
1333
+ self.assertEqual(response.status_code, 200)
1334
+ self.assertTemplateUsed(response, "wagtailforms/submissions_index.html")
1335
+
1336
+ # Check that we got the last page
1337
+ self.assertEqual(
1338
+ response.context["page_obj"].number, response.context["paginator"].num_pages
1339
+ )
1198
1340
 
1199
1341
 
1200
1342
  class TestDeleteFormSubmission(WagtailTestUtils, TestCase):
@@ -1205,16 +1347,30 @@ class TestDeleteFormSubmission(WagtailTestUtils, TestCase):
1205
1347
  self.form_page = Page.objects.get(url_path="/home/contact-us/")
1206
1348
 
1207
1349
  def test_delete_submission_show_confirmation(self):
1350
+ delete_url = reverse(
1351
+ "wagtailforms:delete_submissions", args=(self.form_page.id,)
1352
+ )
1353
+ list_url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,))
1354
+
1208
1355
  response = self.client.get(
1209
1356
  reverse("wagtailforms:delete_submissions", args=(self.form_page.id,))
1210
1357
  + f"?selected-submissions={FormSubmission.objects.first().id}"
1211
1358
  )
1359
+ self.assertEqual(response.status_code, 200)
1212
1360
  # Check show confirm page when HTTP method is GET
1213
1361
  self.assertTemplateUsed(response, "wagtailforms/confirm_delete.html")
1214
1362
 
1215
1363
  # Check that the deletion has not happened with GET request
1216
1364
  self.assertEqual(FormSubmission.objects.count(), 2)
1217
1365
 
1366
+ # The delete form should have a 'next' input that points back to the list page
1367
+ soup = self.get_soup(response.content)
1368
+ form = soup.select_one(f'form[action^="{delete_url}"]')
1369
+ self.assertIsNotNone(form)
1370
+ next_input = form.find("input", {"name": "next"})
1371
+ self.assertIsNotNone(next_input)
1372
+ self.assertEqual(next_input.get("value"), list_url)
1373
+
1218
1374
  def test_delete_submission_with_permissions(self):
1219
1375
  response = self.client.post(
1220
1376
  reverse("wagtailforms:delete_submissions", args=(self.form_page.id,))
@@ -1289,6 +1445,39 @@ class TestDeleteFormSubmission(WagtailTestUtils, TestCase):
1289
1445
  reverse("wagtailforms:list_submissions", args=(self.form_page.id,)),
1290
1446
  )
1291
1447
 
1448
+ def test_delete_submission_with_next_url(self):
1449
+ submission_id = FormSubmission.objects.first().id
1450
+ delete_url = reverse(
1451
+ "wagtailforms:delete_submissions", args=(self.form_page.id,)
1452
+ )
1453
+ list_url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,))
1454
+ next_url = list_url + "?p=2"
1455
+
1456
+ response = self.client.get(
1457
+ reverse("wagtailforms:delete_submissions", args=(self.form_page.id,))
1458
+ + f"?selected-submissions={submission_id}&next={next_url}"
1459
+ )
1460
+ self.assertEqual(response.status_code, 200)
1461
+
1462
+ # The delete form should have a 'next' input that points back to the list page
1463
+ # with the same pagination querystring
1464
+ soup = self.get_soup(response.content)
1465
+ form = soup.select_one(f'form[action^="{delete_url}"]')
1466
+ self.assertIsNotNone(form)
1467
+ next_input = form.find("input", {"name": "next"})
1468
+ self.assertIsNotNone(next_input)
1469
+ self.assertEqual(next_input.get("value"), next_url)
1470
+
1471
+ # Submitting the form should redirect to the next URL
1472
+ response = self.client.post(
1473
+ reverse("wagtailforms:delete_submissions", args=(self.form_page.id,)),
1474
+ {
1475
+ "selected-submissions": submission_id,
1476
+ "next": next_url,
1477
+ },
1478
+ )
1479
+ self.assertRedirects(response, next_url)
1480
+
1292
1481
 
1293
1482
  class TestDeleteCustomFormSubmission(WagtailTestUtils, TestCase):
1294
1483
  fixtures = ["test.json"]
@@ -1483,10 +1672,8 @@ class TestFormsWithCustomSubmissionsList(WagtailTestUtils, TestCase):
1483
1672
  def test_list_submissions_pagination(self):
1484
1673
  self.make_list_submissions()
1485
1674
 
1486
- response = self.client.get(
1487
- reverse("wagtailforms:list_submissions", args=(self.form_page.id,)),
1488
- {"p": 2},
1489
- )
1675
+ list_url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,))
1676
+ response = self.client.get(list_url, {"p": 2})
1490
1677
 
1491
1678
  # Check response
1492
1679
  self.assertEqual(response.status_code, 200)
@@ -1497,6 +1684,18 @@ class TestFormsWithCustomSubmissionsList(WagtailTestUtils, TestCase):
1497
1684
  self.assertContains(response, "Wet my pants excited!", count=50)
1498
1685
  self.assertEqual(response.context["page_obj"].number, 2)
1499
1686
 
1687
+ # The delete form should have a 'next' input that points back to the list page
1688
+ # with the same pagination querystring
1689
+ soup = self.get_soup(response.content)
1690
+ delete_url = reverse(
1691
+ "wagtailforms:delete_submissions", args=(self.form_page.id,)
1692
+ )
1693
+ form = soup.find("form", {"action": delete_url})
1694
+ self.assertIsNotNone(form)
1695
+ next_input = form.find("input", {"name": "next"})
1696
+ self.assertIsNotNone(next_input)
1697
+ self.assertEqual(next_input.get("value"), f"{list_url}?p=2")
1698
+
1500
1699
  def test_list_submissions_csv_export(self):
1501
1700
  response = self.client.get(
1502
1701
  reverse("wagtailforms:list_submissions", args=(self.form_page.id,)),
@@ -1,3 +1,5 @@
1
+ from functools import lru_cache
2
+
1
3
  from django.contrib.contenttypes.models import ContentType
2
4
 
3
5
  from wagtail import hooks
@@ -5,8 +7,6 @@ from wagtail.coreutils import safe_snake_case
5
7
  from wagtail.models import get_page_models
6
8
  from wagtail.permissions import page_permission_policy
7
9
 
8
- _FORM_CONTENT_TYPES = None
9
-
10
10
 
11
11
  def get_field_clean_name(label):
12
12
  """
@@ -16,19 +16,13 @@ def get_field_clean_name(label):
16
16
  return safe_snake_case(label)
17
17
 
18
18
 
19
+ @lru_cache(maxsize=None)
19
20
  def get_form_types():
20
- global _FORM_CONTENT_TYPES
21
- if _FORM_CONTENT_TYPES is None:
22
- from wagtail.contrib.forms.models import FormMixin
23
-
24
- form_models = [
25
- model for model in get_page_models() if issubclass(model, FormMixin)
26
- ]
27
-
28
- _FORM_CONTENT_TYPES = list(
29
- ContentType.objects.get_for_models(*form_models).values()
30
- )
31
- return _FORM_CONTENT_TYPES
21
+ from wagtail.contrib.forms.models import FormMixin
22
+
23
+ form_models = [model for model in get_page_models() if issubclass(model, FormMixin)]
24
+
25
+ return list(ContentType.objects.get_for_models(*form_models).values())
32
26
 
33
27
 
34
28
  def get_forms_for_user(user):