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
@@ -2,21 +2,31 @@ import datetime
2
2
  from collections import OrderedDict
3
3
 
4
4
  from django.contrib.admin.utils import quote
5
+ from django.contrib.contenttypes.models import ContentType
5
6
  from django.core.exceptions import PermissionDenied
7
+ from django.forms import CheckboxSelectMultiple
6
8
  from django.shortcuts import get_object_or_404, redirect
7
9
  from django.urls import reverse
10
+ from django.utils.functional import classproperty
8
11
  from django.utils.translation import gettext, gettext_lazy, ngettext
9
12
  from django.views.generic import TemplateView
10
13
  from django_filters import DateFromToRangeFilter
11
14
 
12
15
  from wagtail.admin import messages
13
- from wagtail.admin.filters import DateRangePickerWidget, WagtailFilterSet
16
+ from wagtail.admin.filters import (
17
+ DateRangePickerWidget,
18
+ MultipleContentTypeFilter,
19
+ WagtailFilterSet,
20
+ )
14
21
  from wagtail.admin.ui.tables import Column, TitleColumn
15
- from wagtail.admin.views import generic
22
+ from wagtail.admin.utils import get_valid_next_url_from_request
23
+ from wagtail.admin.views.generic import PermissionCheckedMixin
16
24
  from wagtail.admin.views.generic.base import BaseListingView
17
25
  from wagtail.admin.views.mixins import SpreadsheetExportMixin
18
- from wagtail.contrib.forms.utils import get_forms_for_user
26
+ from wagtail.admin.views.pages.listing import PageFilterSet, PageListingMixin
27
+ from wagtail.contrib.forms.utils import get_form_types, get_forms_for_user
19
28
  from wagtail.models import Page
29
+ from wagtail.permissions import page_permission_policy
20
30
 
21
31
 
22
32
  def get_submissions_list_view(request, *args, **kwargs):
@@ -39,9 +49,28 @@ class ContentTypeColumn(Column):
39
49
  return context
40
50
 
41
51
 
42
- class FormPagesListView(generic.IndexView):
52
+ class FormPageFilterSet(PageFilterSet):
53
+ content_type = MultipleContentTypeFilter(
54
+ label=gettext_lazy("Page type"),
55
+ queryset=lambda request: ContentType.objects.filter(
56
+ pk__in=[ct.pk for ct in get_form_types()]
57
+ ).order_by("model"),
58
+ widget=CheckboxSelectMultiple,
59
+ )
60
+
61
+
62
+ class FormPagesListView(PageListingMixin, PermissionCheckedMixin, BaseListingView):
43
63
  """Lists the available form pages for the current user"""
44
64
 
65
+ permission_policy = page_permission_policy
66
+ any_permission_required = {
67
+ "add",
68
+ "change",
69
+ "publish",
70
+ "bulk_delete",
71
+ "lock",
72
+ "unlock",
73
+ }
45
74
  template_name = "wagtailforms/index.html"
46
75
  results_template_name = "wagtailforms/index_results.html"
47
76
  context_object_name = "form_pages"
@@ -51,25 +80,36 @@ class FormPagesListView(generic.IndexView):
51
80
  index_results_url_name = "wagtailforms:index_results"
52
81
  page_title = gettext_lazy("Forms")
53
82
  header_icon = "form"
54
- _show_breadcrumbs = True
55
- columns = [
56
- TitleColumn(
57
- "title",
58
- classname="title",
59
- label=gettext_lazy("Title"),
60
- width="50%",
61
- url_name="wagtailforms:list_submissions",
62
- sort_key="title",
63
- ),
64
- ContentTypeColumn(
65
- "content_type",
66
- label=gettext_lazy("Origin"),
67
- width="50%",
68
- sort_key="content_type",
69
- ),
70
- ]
71
83
  model = Page
72
- is_searchable = False
84
+ is_searchable = True
85
+ filterset_class = FormPageFilterSet
86
+
87
+ @classproperty
88
+ def columns(self):
89
+ columns = [
90
+ col for col in PageListingMixin.columns if col.name not in {"title", "type"}
91
+ ]
92
+ columns.insert(
93
+ 1,
94
+ TitleColumn(
95
+ "title",
96
+ classname="title",
97
+ label=gettext_lazy("Title"),
98
+ url_name="wagtailforms:list_submissions",
99
+ sort_key="title",
100
+ width="30%",
101
+ ),
102
+ )
103
+ columns.insert(
104
+ -1,
105
+ ContentTypeColumn(
106
+ "content_type",
107
+ label=gettext_lazy("Origin"),
108
+ sort_key="content_type",
109
+ width="20%",
110
+ ),
111
+ )
112
+ return columns
73
113
 
74
114
  def get_breadcrumbs_items(self):
75
115
  return self.breadcrumbs_items + [
@@ -78,7 +118,8 @@ class FormPagesListView(generic.IndexView):
78
118
 
79
119
  def get_base_queryset(self):
80
120
  """Return the queryset of form pages for this view"""
81
- return get_forms_for_user(self.request.user).select_related("content_type")
121
+ pages = get_forms_for_user(self.request.user).select_related("content_type")
122
+ return self.annotate_queryset(pages)
82
123
 
83
124
 
84
125
  class DeleteSubmissionsView(TemplateView):
@@ -87,7 +128,7 @@ class DeleteSubmissionsView(TemplateView):
87
128
  template_name = "wagtailforms/confirm_delete.html"
88
129
  page = None
89
130
  submissions = None
90
- success_url = "wagtailforms:list_submissions"
131
+ success_url_name = "wagtailforms:list_submissions"
91
132
 
92
133
  def get_queryset(self):
93
134
  """Returns a queryset for the selected submissions"""
@@ -111,7 +152,10 @@ class DeleteSubmissionsView(TemplateView):
111
152
 
112
153
  def get_success_url(self):
113
154
  """Returns the success URL to redirect to after a successful deletion"""
114
- return self.success_url
155
+ next_url = get_valid_next_url_from_request(self.request)
156
+ if next_url:
157
+ return next_url
158
+ return reverse(self.success_url_name, args=(self.page.id,))
115
159
 
116
160
  def dispatch(self, request, *args, **kwargs):
117
161
  """Check permissions, set the page and submissions, handle delete"""
@@ -126,7 +170,7 @@ class DeleteSubmissionsView(TemplateView):
126
170
 
127
171
  if self.request.method == "POST":
128
172
  self.handle_delete(self.submissions)
129
- return redirect(self.get_success_url(), page_id)
173
+ return redirect(self.get_success_url())
130
174
 
131
175
  return super().dispatch(request, *args, **kwargs)
132
176
 
@@ -140,6 +184,7 @@ class DeleteSubmissionsView(TemplateView):
140
184
  "submissions": self.submissions,
141
185
  }
142
186
  )
187
+ context["next_url"] = self.get_success_url()
143
188
 
144
189
  return context
145
190
 
@@ -172,7 +217,6 @@ class SubmissionsListView(SpreadsheetExportMixin, BaseListingView):
172
217
  forms_index_url_name = "wagtailforms:index"
173
218
  index_url_name = "wagtailforms:list_submissions"
174
219
  index_results_url_name = "wagtailforms:list_submissions_results"
175
- _show_breadcrumbs = True
176
220
  show_export_buttons = True
177
221
 
178
222
  def dispatch(self, request, *args, **kwargs):
@@ -319,4 +363,5 @@ class SubmissionsListView(SpreadsheetExportMixin, BaseListingView):
319
363
  }
320
364
  )
321
365
 
366
+ context["next_url"] = self.request.get_full_path()
322
367
  return context
@@ -100,7 +100,7 @@ class AzureBaseBackend(BaseBackend):
100
100
  return {
101
101
  "resource_group_name": self._resource_group_name,
102
102
  "custom_headers": self._custom_headers,
103
- "content_paths": paths,
103
+ "content_paths": set(paths),
104
104
  }
105
105
 
106
106
  def _purge_content(self, paths):
@@ -45,7 +45,7 @@ class CloudfrontBackend(BaseBackend):
45
45
  self.hostnames = list(self.cloudfront_distribution_id.keys())
46
46
 
47
47
  def purge_batch(self, urls):
48
- paths_by_distribution_id = defaultdict(list)
48
+ paths_by_distribution_id = defaultdict(set)
49
49
 
50
50
  for url in urls:
51
51
  url_parsed = urlparse(url)
@@ -69,7 +69,7 @@ class CloudfrontBackend(BaseBackend):
69
69
  distribution_id = self.cloudfront_distribution_id
70
70
 
71
71
  if distribution_id:
72
- paths_by_distribution_id[distribution_id].append(url_parsed.path)
72
+ paths_by_distribution_id[distribution_id].add(url_parsed.path)
73
73
 
74
74
  for distribution_id, paths in paths_by_distribution_id.items():
75
75
  self._create_invalidation(distribution_id, paths)
@@ -0,0 +1,11 @@
1
+ from .base import BaseBackend
2
+
3
+
4
+ class DummyBackend(BaseBackend):
5
+ def __init__(self):
6
+ super().__init__()
7
+
8
+ self.urls = []
9
+
10
+ def purge(self, url) -> None:
11
+ self.urls.append(url)
@@ -360,7 +360,7 @@ class TestBackendConfiguration(SimpleTestCase):
360
360
  backends.get("cloudfront").purge("http://torchbox.com/blog/")
361
361
 
362
362
  _create_invalidation.assert_called_once_with(
363
- "frontend", ["/home/events/christmas/"]
363
+ "frontend", {"/home/events/christmas/"}
364
364
  )
365
365
 
366
366
  self.assertTrue(
@@ -417,12 +417,12 @@ class TestBackendConfiguration(SimpleTestCase):
417
417
  self.assertEqual(backends["default"].cache_netloc, "localhost:8000")
418
418
 
419
419
 
420
- PURGED_URLS = []
420
+ PURGED_URLS = set()
421
421
 
422
422
 
423
423
  class MockBackend(BaseBackend):
424
424
  def purge(self, url):
425
- PURGED_URLS.append(url)
425
+ PURGED_URLS.add(url)
426
426
 
427
427
 
428
428
  class MockCloudflareBackend(CloudflareBackend):
@@ -430,7 +430,7 @@ class MockCloudflareBackend(CloudflareBackend):
430
430
  if len(urls) > self.CHUNK_SIZE:
431
431
  raise Exception("Cloudflare backend is not chunking requests as expected")
432
432
 
433
- PURGED_URLS.extend(urls)
433
+ PURGED_URLS.update(urls)
434
434
 
435
435
 
436
436
  @override_settings(
@@ -444,28 +444,27 @@ class TestCachePurgingFunctions(TestCase):
444
444
  fixtures = ["test.json"]
445
445
 
446
446
  def setUp(self):
447
- # Reset PURGED_URLS to an empty list
448
- PURGED_URLS[:] = []
447
+ PURGED_URLS.clear()
449
448
 
450
449
  def test_purge_url_from_cache(self):
451
450
  purge_url_from_cache("http://localhost/foo")
452
- self.assertEqual(PURGED_URLS, ["http://localhost/foo"])
451
+ self.assertEqual(PURGED_URLS, {"http://localhost/foo"})
453
452
 
454
453
  def test_purge_urls_from_cache(self):
455
454
  purge_urls_from_cache(["http://localhost/foo", "http://localhost/bar"])
456
- self.assertEqual(PURGED_URLS, ["http://localhost/foo", "http://localhost/bar"])
455
+ self.assertEqual(PURGED_URLS, {"http://localhost/foo", "http://localhost/bar"})
457
456
 
458
457
  def test_purge_page_from_cache(self):
459
458
  page = EventIndex.objects.get(url_path="/home/events/")
460
459
  purge_page_from_cache(page)
461
460
  self.assertEqual(
462
- PURGED_URLS, ["http://localhost/events/", "http://localhost/events/past/"]
461
+ PURGED_URLS, {"http://localhost/events/", "http://localhost/events/past/"}
463
462
  )
464
463
 
465
464
  def test_purge_pages_from_cache(self):
466
465
  purge_pages_from_cache(EventIndex.objects.all())
467
466
  self.assertEqual(
468
- PURGED_URLS, ["http://localhost/events/", "http://localhost/events/past/"]
467
+ PURGED_URLS, {"http://localhost/events/", "http://localhost/events/past/"}
469
468
  )
470
469
 
471
470
  def test_purge_batch(self):
@@ -477,11 +476,11 @@ class TestCachePurgingFunctions(TestCase):
477
476
 
478
477
  self.assertEqual(
479
478
  PURGED_URLS,
480
- [
479
+ {
481
480
  "http://localhost/events/",
482
481
  "http://localhost/events/past/",
483
482
  "http://localhost/foo",
484
- ],
483
+ },
485
484
  )
486
485
 
487
486
  @override_settings(
@@ -496,14 +495,14 @@ class TestCachePurgingFunctions(TestCase):
496
495
  with self.assertLogs(level="INFO") as log_output:
497
496
  purge_url_from_cache("http://localhost/foo")
498
497
 
499
- self.assertEqual(PURGED_URLS, [])
498
+ self.assertEqual(PURGED_URLS, set())
500
499
  self.assertIn(
501
500
  "Unable to find purge backend for localhost",
502
501
  log_output.output[0],
503
502
  )
504
503
 
505
504
  purge_url_from_cache("http://example.com/foo")
506
- self.assertEqual(PURGED_URLS, ["http://example.com/foo"])
505
+ self.assertEqual(PURGED_URLS, {"http://example.com/foo"})
507
506
 
508
507
 
509
508
  @override_settings(
@@ -518,7 +517,7 @@ class TestCachePurgingFunctions(TestCase):
518
517
  class TestCloudflareCachePurgingFunctions(TestCase):
519
518
  def setUp(self):
520
519
  # Reset PURGED_URLS to an empty list
521
- PURGED_URLS[:] = []
520
+ PURGED_URLS.clear()
522
521
 
523
522
  def test_cloudflare_purge_batch_chunked(self):
524
523
  batch = PurgeBatch()
@@ -526,7 +525,7 @@ class TestCloudflareCachePurgingFunctions(TestCase):
526
525
  batch.add_urls(urls)
527
526
  batch.purge()
528
527
 
529
- self.assertCountEqual(PURGED_URLS, urls)
528
+ self.assertCountEqual(PURGED_URLS, set(urls))
530
529
 
531
530
 
532
531
  @override_settings(
@@ -541,20 +540,20 @@ class TestCachePurgingSignals(TestCase):
541
540
 
542
541
  def setUp(self):
543
542
  # Reset PURGED_URLS to an empty list
544
- PURGED_URLS[:] = []
543
+ PURGED_URLS.clear()
545
544
 
546
545
  def test_purge_on_publish(self):
547
546
  page = EventIndex.objects.get(url_path="/home/events/")
548
547
  page.save_revision().publish()
549
548
  self.assertEqual(
550
- PURGED_URLS, ["http://localhost/events/", "http://localhost/events/past/"]
549
+ PURGED_URLS, {"http://localhost/events/", "http://localhost/events/past/"}
551
550
  )
552
551
 
553
552
  def test_purge_on_unpublish(self):
554
553
  page = EventIndex.objects.get(url_path="/home/events/")
555
554
  page.unpublish()
556
555
  self.assertEqual(
557
- PURGED_URLS, ["http://localhost/events/", "http://localhost/events/past/"]
556
+ PURGED_URLS, {"http://localhost/events/", "http://localhost/events/past/"}
558
557
  )
559
558
 
560
559
  def test_purge_with_unroutable_page(self):
@@ -562,7 +561,7 @@ class TestCachePurgingSignals(TestCase):
562
561
  page = EventIndex(title="new top-level page")
563
562
  root.add_child(instance=page)
564
563
  page.save_revision().publish()
565
- self.assertEqual(PURGED_URLS, [])
564
+ self.assertEqual(PURGED_URLS, set())
566
565
 
567
566
  @override_settings(
568
567
  ROOT_URLCONF="wagtail.test.urls_multilang",
@@ -570,20 +569,19 @@ class TestCachePurgingSignals(TestCase):
570
569
  WAGTAILFRONTENDCACHE_LANGUAGES=["en", "fr", "pt-br"],
571
570
  )
572
571
  def test_purge_on_publish_in_multilang_env(self):
573
- PURGED_URLS[:] = [] # reset PURGED_URLS to the empty list
574
572
  page = EventIndex.objects.get(url_path="/home/events/")
575
573
  page.save_revision().publish()
576
574
 
577
575
  self.assertEqual(
578
576
  PURGED_URLS,
579
- [
577
+ {
580
578
  "http://localhost/en/events/",
581
579
  "http://localhost/en/events/past/",
582
580
  "http://localhost/fr/events/",
583
581
  "http://localhost/fr/events/past/",
584
582
  "http://localhost/pt-br/events/",
585
583
  "http://localhost/pt-br/events/past/",
586
- ],
584
+ },
587
585
  )
588
586
 
589
587
  @override_settings(
@@ -593,18 +591,17 @@ class TestCachePurgingSignals(TestCase):
593
591
  WAGTAIL_CONTENT_LANGUAGES=[("en", "English"), ("fr", "French")],
594
592
  )
595
593
  def test_purge_on_publish_with_i18n_enabled(self):
596
- PURGED_URLS[:] = [] # reset PURGED_URLS to the empty list
597
594
  page = EventIndex.objects.get(url_path="/home/events/")
598
595
  page.save_revision().publish()
599
596
 
600
597
  self.assertEqual(
601
598
  PURGED_URLS,
602
- [
599
+ {
603
600
  "http://localhost/en/events/",
604
601
  "http://localhost/en/events/past/",
605
602
  "http://localhost/fr/events/",
606
603
  "http://localhost/fr/events/past/",
607
- ],
604
+ },
608
605
  )
609
606
 
610
607
  @override_settings(
@@ -614,12 +611,11 @@ class TestCachePurgingSignals(TestCase):
614
611
  )
615
612
  def test_purge_on_publish_without_i18n_enabled(self):
616
613
  # It should ignore WAGTAIL_CONTENT_LANGUAGES as WAGTAIL_I18N_ENABLED isn't set
617
- PURGED_URLS[:] = [] # reset PURGED_URLS to the empty list
618
614
  page = EventIndex.objects.get(url_path="/home/events/")
619
615
  page.save_revision().publish()
620
616
  self.assertEqual(
621
617
  PURGED_URLS,
622
- ["http://localhost/en/events/", "http://localhost/en/events/past/"],
618
+ {"http://localhost/en/events/", "http://localhost/en/events/past/"},
623
619
  )
624
620
 
625
621
 
@@ -633,13 +629,13 @@ class TestPurgeBatchClass(TestCase):
633
629
  batch = PurgeBatch()
634
630
  batch.add_url("http://localhost/foo")
635
631
 
636
- self.assertEqual(batch.urls, ["http://localhost/foo"])
632
+ self.assertEqual(batch.urls, {"http://localhost/foo"})
637
633
 
638
634
  def test_add_urls(self):
639
635
  batch = PurgeBatch()
640
636
  batch.add_urls(["http://localhost/foo", "http://localhost/bar"])
641
637
 
642
- self.assertEqual(batch.urls, ["http://localhost/foo", "http://localhost/bar"])
638
+ self.assertEqual(batch.urls, {"http://localhost/foo", "http://localhost/bar"})
643
639
 
644
640
  def test_add_page(self):
645
641
  page = EventIndex.objects.get(url_path="/home/events/")
@@ -648,7 +644,7 @@ class TestPurgeBatchClass(TestCase):
648
644
  batch.add_page(page)
649
645
 
650
646
  self.assertEqual(
651
- batch.urls, ["http://localhost/events/", "http://localhost/events/past/"]
647
+ batch.urls, {"http://localhost/events/", "http://localhost/events/past/"}
652
648
  )
653
649
 
654
650
  def test_add_pages(self):
@@ -656,7 +652,7 @@ class TestPurgeBatchClass(TestCase):
656
652
  batch.add_pages(EventIndex.objects.all())
657
653
 
658
654
  self.assertEqual(
659
- batch.urls, ["http://localhost/events/", "http://localhost/events/past/"]
655
+ batch.urls, {"http://localhost/events/", "http://localhost/events/past/"}
660
656
  )
661
657
 
662
658
  def test_multiple_calls(self):
@@ -669,11 +665,11 @@ class TestPurgeBatchClass(TestCase):
669
665
 
670
666
  self.assertEqual(
671
667
  batch.urls,
672
- [
668
+ {
673
669
  "http://localhost/events/",
674
670
  "http://localhost/events/past/",
675
671
  "http://localhost/foo",
676
- ],
672
+ },
677
673
  )
678
674
 
679
675
  @mock.patch("wagtail.contrib.frontend_cache.backends.cloudflare.requests.delete")
@@ -696,10 +692,8 @@ class TestPurgeBatchClass(TestCase):
696
692
  )
697
693
  requests_delete_mock.side_effect = http_error
698
694
 
699
- page = EventIndex.objects.get(url_path="/home/events/")
700
-
701
695
  batch = PurgeBatch()
702
- batch.add_page(page)
696
+ batch.add_url("http://localhost/events/")
703
697
 
704
698
  with self.assertLogs(level="ERROR") as log_output:
705
699
  batch.purge(backend_settings=backend_settings)
@@ -64,6 +64,15 @@ def purge_url_from_cache(url, backend_settings=None, backends=None):
64
64
 
65
65
 
66
66
  def purge_urls_from_cache(urls, backend_settings=None, backends=None):
67
+ if not urls:
68
+ return
69
+
70
+ backends = get_backends(backend_settings, backends)
71
+
72
+ # If no backends are configured, there's nothing to do
73
+ if not backends:
74
+ return
75
+
67
76
  # Convert each url to urls one for each managed language (WAGTAILFRONTENDCACHE_LANGUAGES setting).
68
77
  # The managed languages are common to all the defined backends.
69
78
  # This depends on settings.USE_I18N
@@ -105,8 +114,6 @@ def purge_urls_from_cache(urls, backend_settings=None, backends=None):
105
114
  for url in urls:
106
115
  urls_by_hostname[urlsplit(url).netloc].append(url)
107
116
 
108
- backends = get_backends(backend_settings, backends)
109
-
110
117
  for hostname, urls in urls_by_hostname.items():
111
118
  backends_for_hostname = {
112
119
  backend_name: backend
@@ -150,14 +157,14 @@ class PurgeBatch:
150
157
  """Represents a list of URLs to be purged in a single request"""
151
158
 
152
159
  def __init__(self, urls=None):
153
- self.urls = []
160
+ self.urls = set()
154
161
 
155
162
  if urls is not None:
156
163
  self.add_urls(urls)
157
164
 
158
165
  def add_url(self, url):
159
166
  """Adds a single URL"""
160
- self.urls.append(url)
167
+ self.urls.add(url)
161
168
 
162
169
  def add_urls(self, urls):
163
170
  """
@@ -166,7 +173,7 @@ class PurgeBatch:
166
173
  This is equivalent to running ``.add_url(url)`` on each URL
167
174
  individually
168
175
  """
169
- self.urls.extend(urls)
176
+ self.urls.update(urls)
170
177
 
171
178
  def add_page(self, page):
172
179
  """
@@ -5,13 +5,14 @@
5
5
  # Translators:
6
6
  # Philip Crisp, 2022
7
7
  # Philip Crisp, 2022
8
+ # Philip Lindsay-Crisp, 2024
8
9
  msgid ""
9
10
  msgstr ""
10
11
  "Project-Id-Version: Wagtail\n"
11
12
  "Report-Msgid-Bugs-To: \n"
12
13
  "POT-Creation-Date: 2024-08-07 10:06+0100\n"
13
14
  "PO-Revision-Date: 2014-02-20 21:04+0000\n"
14
- "Last-Translator: Philip Crisp, 2022\n"
15
+ "Last-Translator: Philip Lindsay-Crisp, 2024\n"
15
16
  "Language-Team: Welsh (http://app.transifex.com/torchbox/wagtail/language/"
16
17
  "cy/)\n"
17
18
  "MIME-Version: 1.0\n"
@@ -103,6 +104,9 @@ msgstr "dros dro"
103
104
  msgid "redirect"
104
105
  msgstr "ailgyfeirio"
105
106
 
107
+ msgid "redirects"
108
+ msgstr "ailgyfeirio"
109
+
106
110
  msgid "Add redirect"
107
111
  msgstr "Ychwanegu ailgyfeiriad"
108
112
 
@@ -115,6 +119,17 @@ msgstr "Ailgyfeiriadau"
115
119
  msgid "Import redirects"
116
120
  msgstr "Mewnforio ailgyfeiriadau"
117
121
 
122
+ msgid ""
123
+ "<p>Select a file where redirects are separated into rows and contains the "
124
+ "columns representing <code>from</code> and <code>to</code> (they can be "
125
+ "named anything).</p> <p>After submitting you will be taken to a confirmation "
126
+ "view where you can customize your redirects before import.</p>"
127
+ msgstr ""
128
+ "<p>Dewiswch ffeil lle mae ailgyfeiriadau wedi'u gwahanu'n rhesi ac yn "
129
+ "cynnwys y colofnau sy'n cynrychioli <code>o</code> a <code>i</code> (gellir "
130
+ "eu henwi yn unrhyw beth).</p> <p>Ar ôl cyflwyno byddwch yn cael eich tywys i "
131
+ "olwg cadarnhau lle gallwch addasu eich ailgyfeiriadau cyn mewnforio.</p>"
132
+
118
133
  msgid "Import"
119
134
  msgstr "Mewnforio"
120
135