wagtail 7.1.1__py3-none-any.whl → 7.2rc1__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 (345) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_page.py +1 -1
  3. wagtail/actions/create_alias.py +1 -1
  4. wagtail/actions/delete_page.py +1 -1
  5. wagtail/actions/publish_page_revision.py +1 -1
  6. wagtail/actions/publish_revision.py +1 -1
  7. wagtail/actions/revert_to_page_revision.py +1 -1
  8. wagtail/actions/unpublish.py +1 -1
  9. wagtail/actions/unpublish_page.py +1 -1
  10. wagtail/admin/auth.py +3 -1
  11. wagtail/admin/checks.py +2 -2
  12. wagtail/admin/filters.py +28 -1
  13. wagtail/admin/forms/collections.py +1 -1
  14. wagtail/admin/forms/comments.py +1 -1
  15. wagtail/admin/forms/models.py +1 -1
  16. wagtail/admin/forms/pages.py +1 -1
  17. wagtail/admin/forms/tags.py +1 -1
  18. wagtail/admin/locale/cs/LC_MESSAGES/django.mo +0 -0
  19. wagtail/admin/locale/cs/LC_MESSAGES/django.po +25 -1
  20. wagtail/admin/locale/en/LC_MESSAGES/django.po +278 -192
  21. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +29 -15
  22. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  23. wagtail/admin/locale/it/LC_MESSAGES/django.po +3 -2
  24. wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
  25. wagtail/admin/locale/nl/LC_MESSAGES/django.po +57 -3
  26. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.mo +0 -0
  27. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.po +8 -2
  28. wagtail/admin/locale/ru/LC_MESSAGES/django.mo +0 -0
  29. wagtail/admin/locale/ru/LC_MESSAGES/django.po +58 -1
  30. wagtail/admin/locale/tr/LC_MESSAGES/django.mo +0 -0
  31. wagtail/admin/locale/tr/LC_MESSAGES/django.po +3 -2
  32. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  33. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +2 -2
  40. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  42. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/icons.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  48. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  49. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  51. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  52. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  53. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  54. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  55. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  56. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +2 -2
  57. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-modal.js +1 -1
  58. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-transition.js +1 -1
  59. wagtail/admin/static/wagtailadmin/js/vendor/jquery-3.6.0.min.js +1 -1
  60. wagtail/admin/static/wagtailadmin/js/vendor/jquery-ui-1.13.2.min.js +1 -1
  61. wagtail/admin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js +1 -1
  62. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload-process.js +1 -1
  63. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload.js +1 -1
  64. wagtail/admin/static/wagtailadmin/js/vendor/jquery.iframe-transport.js +1 -1
  65. wagtail/admin/static/wagtailadmin/js/vendor/tag-it.js +1 -1
  66. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  67. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +1 -1
  68. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  69. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  70. wagtail/admin/templates/wagtailadmin/account/account.html +2 -0
  71. wagtail/admin/templates/wagtailadmin/base.html +14 -0
  72. wagtail/admin/templates/wagtailadmin/generic/chooser/chooser.html +2 -1
  73. wagtail/admin/templates/wagtailadmin/generic/chooser/creation_form.html +2 -1
  74. wagtail/admin/templates/wagtailadmin/generic/form.html +3 -1
  75. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  76. wagtail/admin/templates/wagtailadmin/panels/object_list.html +1 -1
  77. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +3 -2
  78. wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  80. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +19 -0
  81. wagtail/admin/templates/wagtailadmin/shared/panel.html +1 -1
  82. wagtail/admin/templates/wagtailadmin/shared/set_privacy.html +15 -0
  83. wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +28 -1
  84. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +2 -2
  85. wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_header.html → tables/ordering_header.html} +2 -2
  86. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +1 -1
  87. wagtail/admin/templates/wagtailadmin/userbar/base.html +6 -3
  88. wagtail/admin/templates/wagtailadmin/userbar/item_admin.html +2 -2
  89. wagtail/admin/templates/wagtailadmin/userbar/item_page_add.html +2 -2
  90. wagtail/admin/templates/wagtailadmin/userbar/item_page_edit.html +2 -2
  91. wagtail/admin/templates/wagtailadmin/userbar/item_page_explore.html +2 -2
  92. wagtail/admin/templates/wagtailadmin/widgets/{daterange_input.html → range_input.html} +1 -1
  93. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/chooser.html +4 -2
  94. wagtail/admin/templatetags/wagtailadmin_tags.py +56 -22
  95. wagtail/admin/tests/api/test_pages.py +7 -7
  96. wagtail/admin/tests/api/test_renderer_classes.py +16 -0
  97. wagtail/admin/tests/pages/test_create_page.py +34 -2
  98. wagtail/admin/tests/pages/test_edit_page.py +128 -14
  99. wagtail/admin/tests/pages/test_explorer_view.py +34 -7
  100. wagtail/admin/tests/pages/test_reorder_page.py +11 -0
  101. wagtail/admin/tests/test_collections_views.py +12 -0
  102. wagtail/admin/tests/test_edit_handlers.py +3 -3
  103. wagtail/admin/tests/test_filters.py +2 -2
  104. wagtail/admin/tests/test_keyboard_shortcuts.py +52 -2
  105. wagtail/admin/tests/test_menu.py +0 -2
  106. wagtail/admin/tests/test_privacy.py +16 -16
  107. wagtail/admin/tests/test_templatetags.py +137 -0
  108. wagtail/admin/tests/test_userbar.py +75 -35
  109. wagtail/admin/tests/test_views_generic.py +34 -0
  110. wagtail/admin/tests/test_workflows.py +34 -0
  111. wagtail/admin/tests/viewsets/test_model_viewset.py +322 -0
  112. wagtail/admin/ui/tables/orderable.py +73 -0
  113. wagtail/admin/ui/tables/pages.py +3 -13
  114. wagtail/admin/userbar.py +6 -1
  115. wagtail/admin/views/collection_privacy.py +6 -2
  116. wagtail/admin/views/generic/__init__.py +1 -0
  117. wagtail/admin/views/generic/mixins.py +20 -2
  118. wagtail/admin/views/generic/models.py +67 -1
  119. wagtail/admin/views/generic/ordering.py +79 -0
  120. wagtail/admin/views/home.py +3 -3
  121. wagtail/admin/views/page_privacy.py +5 -2
  122. wagtail/admin/views/pages/create.py +1 -1
  123. wagtail/admin/views/pages/edit.py +2 -2
  124. wagtail/admin/views/pages/listing.py +7 -42
  125. wagtail/admin/views/pages/move.py +1 -1
  126. wagtail/admin/views/pages/ordering.py +1 -1
  127. wagtail/admin/viewsets/base.py +1 -1
  128. wagtail/admin/viewsets/model.py +49 -1
  129. wagtail/admin/wagtail_hooks.py +2 -1
  130. wagtail/admin/widgets/slug.py +10 -10
  131. wagtail/api/v2/serializers.py +1 -1
  132. wagtail/api/v2/tests/test_renderer_classes.py +32 -0
  133. wagtail/apps.py +2 -0
  134. wagtail/bin/wagtail.py +1 -1
  135. wagtail/blocks/struct_block.py +2 -1
  136. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +14 -14
  137. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.mo +0 -0
  138. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.po +19 -2
  139. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.mo +0 -0
  140. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +18 -1
  141. wagtail/contrib/frontend_cache/tests.py +4 -2
  142. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +4 -4
  143. wagtail/contrib/redirects/tests/test_tmp_storages.py +20 -0
  144. wagtail/contrib/redirects/tmp_storages.py +1 -1
  145. wagtail/contrib/redirects/views.py +3 -3
  146. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +3 -3
  147. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.mo +0 -0
  148. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +43 -3
  149. wagtail/contrib/search_promotions/static/wagtailsearchpromotions/js/query-chooser-modal.js +1 -1
  150. wagtail/contrib/search_promotions/views/settings.py +2 -2
  151. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.mo +0 -0
  152. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.po +6 -1
  153. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +1 -1
  154. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.mo +0 -0
  155. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.po +6 -2
  156. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.mo +0 -0
  157. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +6 -1
  158. wagtail/contrib/settings/tests/site_specific/test_admin.py +40 -6
  159. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  160. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  161. wagtail/contrib/styleguide/templates/wagtailstyleguide/base.html +5 -5
  162. wagtail/contrib/table_block/blocks.py +1 -0
  163. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +5 -1
  164. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  165. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  166. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  167. wagtail/coreutils.py +5 -5
  168. wagtail/documents/forms.py +18 -1
  169. wagtail/documents/locale/en/LC_MESSAGES/django.po +10 -10
  170. wagtail/documents/locale/nl/LC_MESSAGES/django.mo +0 -0
  171. wagtail/documents/locale/nl/LC_MESSAGES/django.po +9 -0
  172. wagtail/documents/locale/ru/LC_MESSAGES/django.mo +0 -0
  173. wagtail/documents/locale/ru/LC_MESSAGES/django.po +9 -0
  174. wagtail/documents/models.py +1 -1
  175. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  176. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  177. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  178. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  179. wagtail/documents/templates/wagtaildocs/documents/add.html +0 -34
  180. wagtail/documents/tests/test_admin_views.py +132 -26
  181. wagtail/documents/tests/test_collection_privacy.py +18 -4
  182. wagtail/documents/tests/test_form_overrides.py +1 -1
  183. wagtail/documents/tests/test_search.py +21 -8
  184. wagtail/documents/views/documents.py +1 -1
  185. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  186. wagtail/embeds/static/wagtailembeds/js/embed-chooser-modal.js +1 -1
  187. wagtail/images/forms.py +16 -1
  188. wagtail/images/locale/cs/LC_MESSAGES/django.mo +0 -0
  189. wagtail/images/locale/cs/LC_MESSAGES/django.po +12 -1
  190. wagtail/images/locale/en/LC_MESSAGES/django.po +57 -46
  191. wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
  192. wagtail/images/locale/nl/LC_MESSAGES/django.po +37 -14
  193. wagtail/images/locale/ru/LC_MESSAGES/django.mo +0 -0
  194. wagtail/images/locale/ru/LC_MESSAGES/django.po +20 -1
  195. wagtail/images/models.py +1 -1
  196. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  197. wagtail/images/static/wagtailimages/js/focal-point-chooser.js +1 -1
  198. wagtail/images/static/wagtailimages/js/image-block.js +1 -1
  199. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  200. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  201. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  202. wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
  203. wagtail/images/static/wagtailimages/js/vendor/jquery.Jcrop.min.js +1 -1
  204. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
  205. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-validate.js +1 -1
  206. wagtail/images/static/wagtailimages/js/vendor/load-image.min.js +1 -1
  207. wagtail/images/templates/wagtailimages/chooser/chooser.html +22 -13
  208. wagtail/images/templates/wagtailimages/chooser/image_preview_column_cell.html +10 -0
  209. wagtail/images/templates/wagtailimages/chooser/results.html +24 -20
  210. wagtail/images/templates/wagtailimages/chooser/title_column_cell.html +15 -0
  211. wagtail/images/templates/wagtailimages/images/add.html +0 -34
  212. wagtail/images/templates/wagtailimages/images/index.html +3 -3
  213. wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
  214. wagtail/images/templates/wagtailimages/images/layout_toggle_button.html +8 -7
  215. wagtail/images/templatetags/wagtailimages_tags.py +2 -2
  216. wagtail/images/tests/test_admin_views.py +87 -0
  217. wagtail/images/tests/test_form_overrides.py +1 -1
  218. wagtail/images/tests/test_models.py +48 -9
  219. wagtail/images/views/chooser.py +66 -2
  220. wagtail/locale/en/LC_MESSAGES/django.po +55 -55
  221. wagtail/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  222. wagtail/locale/is_IS/LC_MESSAGES/django.po +3 -3
  223. wagtail/locale/nl/LC_MESSAGES/django.mo +0 -0
  224. wagtail/locale/nl/LC_MESSAGES/django.po +11 -2
  225. wagtail/locale/ru/LC_MESSAGES/django.mo +0 -0
  226. wagtail/locale/ru/LC_MESSAGES/django.po +11 -1
  227. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  228. wagtail/locales/locale/nl/LC_MESSAGES/django.mo +0 -0
  229. wagtail/locales/locale/nl/LC_MESSAGES/django.po +12 -1
  230. wagtail/locales/locale/ru/LC_MESSAGES/django.mo +0 -0
  231. wagtail/locales/locale/ru/LC_MESSAGES/django.po +10 -1
  232. wagtail/locales/views.py +2 -2
  233. wagtail/models/orderable.py +10 -0
  234. wagtail/models/pages.py +9 -11
  235. wagtail/models/sites.py +1 -1
  236. wagtail/models/workflows.py +8 -5
  237. wagtail/project_template/home/tests.py +6 -7
  238. wagtail/project_template/project_name/settings/base.py +9 -9
  239. wagtail/project_template/requirements.txt +1 -1
  240. wagtail/query.py +7 -2
  241. wagtail/rich_text/rewriters.py +1 -1
  242. wagtail/search/apps.py +4 -49
  243. wagtail/search/backends/__init__.py +1 -113
  244. wagtail/search/backends/base.py +1 -547
  245. wagtail/search/backends/database/__init__.py +1 -50
  246. wagtail/search/backends/database/fallback.py +1 -253
  247. wagtail/search/backends/database/mysql/mysql.py +1 -700
  248. wagtail/search/backends/database/mysql/query.py +1 -258
  249. wagtail/search/backends/database/postgres/postgres.py +1 -749
  250. wagtail/search/backends/database/postgres/query.py +1 -83
  251. wagtail/search/backends/database/postgres/weights.py +1 -63
  252. wagtail/search/backends/database/sqlite/query.py +1 -294
  253. wagtail/search/backends/database/sqlite/sqlite.py +1 -719
  254. wagtail/search/backends/database/sqlite/utils.py +1 -35
  255. wagtail/search/backends/deprecation.py +45 -0
  256. wagtail/search/backends/elasticsearch7.py +18 -1260
  257. wagtail/search/backends/elasticsearch8.py +21 -96
  258. wagtail/search/backends/elasticsearch9.py +35 -0
  259. wagtail/search/backends/opensearch2.py +35 -0
  260. wagtail/search/backends/opensearch3.py +35 -0
  261. wagtail/search/index.py +1 -358
  262. wagtail/search/locale/en/LC_MESSAGES/django.po +2 -10
  263. wagtail/search/management/commands/update_index.py +1 -205
  264. wagtail/search/management/commands/wagtail_update_index.py +1 -4
  265. wagtail/search/models.py +32 -158
  266. wagtail/search/query.py +1 -114
  267. wagtail/search/queryset.py +1 -43
  268. wagtail/search/signal_handlers.py +1 -24
  269. wagtail/search/tasks.py +1 -10
  270. wagtail/search/tests/test_elasticsearch.py +22 -0
  271. wagtail/search/utils.py +1 -206
  272. wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
  273. wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -3
  274. wagtail/snippets/locale/ru/LC_MESSAGES/django.mo +0 -0
  275. wagtail/snippets/locale/ru/LC_MESSAGES/django.po +8 -1
  276. wagtail/snippets/locale/tr/LC_MESSAGES/django.mo +0 -0
  277. wagtail/snippets/locale/tr/LC_MESSAGES/django.po +8 -1
  278. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  279. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  280. wagtail/snippets/tests/test_preview.py +5 -6
  281. wagtail/snippets/tests/test_reordering.py +319 -0
  282. wagtail/snippets/tests/test_snippets.py +65 -12
  283. wagtail/snippets/views/snippets.py +16 -0
  284. wagtail/test/numberformat.py +30 -0
  285. wagtail/test/settings.py +35 -12
  286. wagtail/test/testapp/fields.py +12 -0
  287. wagtail/test/testapp/migrations/0056_commentablejsonpage.py +50 -0
  288. wagtail/test/testapp/migrations/0057_featurecompletetoy_sort_order.py +23 -0
  289. wagtail/test/testapp/migrations/0058_customlocktask.py +31 -0
  290. wagtail/test/testapp/models.py +27 -0
  291. wagtail/test/testapp/urls.py +1 -0
  292. wagtail/test/testapp/views.py +18 -2
  293. wagtail/test/utils/page_tests.py +17 -17
  294. wagtail/test/utils/template_tests.py +4 -6
  295. wagtail/test/utils/wagtail_tests.py +1 -2
  296. wagtail/tests/test_blocks.py +15 -0
  297. wagtail/tests/test_page_model.py +15 -0
  298. wagtail/{search/tests → tests}/test_page_search.py +29 -2
  299. wagtail/tests/test_search_fields.py +69 -0
  300. wagtail/tests/test_tests.py +62 -6
  301. wagtail/tests/test_workflow.py +25 -1
  302. wagtail/users/locale/cs/LC_MESSAGES/django.mo +0 -0
  303. wagtail/users/locale/cs/LC_MESSAGES/django.po +3 -0
  304. wagtail/users/locale/en/LC_MESSAGES/django.po +2 -2
  305. wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
  306. wagtail/users/locale/nl/LC_MESSAGES/django.po +6 -3
  307. wagtail/users/locale/ru/LC_MESSAGES/django.mo +0 -0
  308. wagtail/users/locale/ru/LC_MESSAGES/django.po +5 -1
  309. wagtail/users/locale/tr/LC_MESSAGES/django.mo +0 -0
  310. wagtail/users/locale/tr/LC_MESSAGES/django.po +78 -4
  311. wagtail/users/templates/wagtailusers/users/create.html +2 -0
  312. wagtail/users/templates/wagtailusers/users/edit.html +2 -0
  313. wagtail/users/tests/test_admin_views.py +4 -0
  314. wagtail/users/views/users.py +1 -1
  315. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/METADATA +7 -6
  316. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/RECORD +322 -328
  317. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +0 -13
  318. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +0 -13
  319. wagtail/search/tests/__init__.py +0 -0
  320. wagtail/search/tests/elasticsearch_common_tests.py +0 -251
  321. wagtail/search/tests/test_backends.py +0 -1215
  322. wagtail/search/tests/test_db_backend.py +0 -62
  323. wagtail/search/tests/test_elasticsearch7_backend.py +0 -1452
  324. wagtail/search/tests/test_elasticsearch8_backend.py +0 -15
  325. wagtail/search/tests/test_index_functions.py +0 -256
  326. wagtail/search/tests/test_indexed_class.py +0 -157
  327. wagtail/search/tests/test_mysql_backend.py +0 -192
  328. wagtail/search/tests/test_postgres_backend.py +0 -210
  329. wagtail/search/tests/test_queries.py +0 -332
  330. wagtail/search/tests/test_related_fields.py +0 -102
  331. wagtail/search/tests/test_sqlite_backend.py +0 -52
  332. wagtail/test/search/__init__.py +0 -0
  333. wagtail/test/search/apps.py +0 -9
  334. wagtail/test/search/fixtures/search.json +0 -545
  335. wagtail/test/search/migrations/0001_initial.py +0 -146
  336. wagtail/test/search/migrations/0002_bookunindexed.py +0 -43
  337. wagtail/test/search/migrations/0003_book_summary.py +0 -18
  338. wagtail/test/search/migrations/__init__.py +0 -0
  339. wagtail/test/search/models.py +0 -137
  340. /wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_cell.html → tables/ordering_cell.html} +0 -0
  341. /wagtail/{search/checks.py → checks.py} +0 -0
  342. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/WHEEL +0 -0
  343. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/entry_points.txt +0 -0
  344. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/licenses/LICENSE +0 -0
  345. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,31 @@
1
+ # Generated by Django 5.1.6 on 2025-07-14 16:16
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("tests", "0057_featurecompletetoy_sort_order"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name="CustomLockTask",
16
+ fields=[
17
+ (
18
+ "task_ptr",
19
+ models.OneToOneField(
20
+ auto_created=True,
21
+ on_delete=django.db.models.deletion.CASCADE,
22
+ parent_link=True,
23
+ primary_key=True,
24
+ serialize=False,
25
+ to="wagtailcore.task",
26
+ ),
27
+ ),
28
+ ],
29
+ bases=("wagtailcore.task",),
30
+ ),
31
+ ]
@@ -88,6 +88,8 @@ from wagtail.search import index
88
88
  from wagtail.snippets.blocks import SnippetChooserBlock
89
89
  from wagtail.snippets.models import register_snippet
90
90
 
91
+ from ...locks import WorkflowLock
92
+ from .fields import CommentableJSONField
91
93
  from .forms import FormClassAdditionalFieldPageForm, ValidatedPageForm
92
94
 
93
95
  EVENT_AUDIENCE_CHOICES = (
@@ -1301,6 +1303,7 @@ class FullFeaturedSnippet(
1301
1303
  LockableMixin,
1302
1304
  RevisionMixin,
1303
1305
  TranslatableMixin,
1306
+ Orderable,
1304
1307
  index.Indexed,
1305
1308
  models.Model,
1306
1309
  ):
@@ -2448,6 +2451,18 @@ class UserApprovalTask(Task):
2448
2451
  return "Only a specific user can approve this task"
2449
2452
 
2450
2453
 
2454
+ class CustomWorkflowLock(WorkflowLock):
2455
+ def get_message(self, user):
2456
+ return "If there is a door, there must be a key"
2457
+
2458
+
2459
+ class CustomLockTask(Task):
2460
+ lock_class = CustomWorkflowLock
2461
+
2462
+ def locked_for_user(self, obj, user):
2463
+ return True
2464
+
2465
+
2451
2466
  # StreamField media definitions must not be evaluated at startup (e.g. during system checks) -
2452
2467
  # these may fail if e.g. ManifestStaticFilesStorage is in use and collectstatic has not been run.
2453
2468
  # Check this with a media definition that deliberately errors; if media handling is not set up
@@ -2587,6 +2602,8 @@ class FeatureCompleteToy(index.Indexed, models.Model):
2587
2602
  )
2588
2603
  name = models.CharField(max_length=255)
2589
2604
  release_date = models.DateField(default=datetime.date.today)
2605
+ sort_order = models.IntegerField(null=True, blank=True)
2606
+ sort_order_field = "sort_order"
2590
2607
 
2591
2608
  search_fields = [
2592
2609
  index.SearchField("name"),
@@ -2676,3 +2693,13 @@ class RequiredDatePage(Page):
2676
2693
  TitleFieldPanel("title", classname="title"),
2677
2694
  FieldPanel("deadline"),
2678
2695
  ]
2696
+
2697
+
2698
+ class CommentableJSONPage(Page):
2699
+ commentable_body = CommentableJSONField()
2700
+ uncommentable_body = models.JSONField()
2701
+ stream_body = StreamField(
2702
+ [
2703
+ ("text", CharBlock()),
2704
+ ]
2705
+ )
@@ -6,6 +6,7 @@ urlpatterns = [
6
6
  path("bob-only-zone", views.bob_only_zone, name="testapp_bob_only_zone"),
7
7
  path("messages/", views.message_test, name="testapp_message_test"),
8
8
  path("test-index/", views.TestIndexView.as_view(), name="testapp_generic_index"),
9
+ path("test-create/", views.TestCreateView.as_view(), name="testapp_generic_create"),
9
10
  path(
10
11
  "test-edit/<str:pk>/", views.TestEditView.as_view(), name="testapp_generic_edit"
11
12
  ),
@@ -14,7 +14,13 @@ from wagtail.admin.auth import user_passes_test
14
14
  from wagtail.admin.filters import WagtailFilterSet
15
15
  from wagtail.admin.panels import FieldPanel
16
16
  from wagtail.admin.ui.tables import BooleanColumn, Column, UpdatedAtColumn
17
- from wagtail.admin.views.generic import DeleteView, EditView, IndexView, InspectView
17
+ from wagtail.admin.views.generic import (
18
+ CreateView,
19
+ DeleteView,
20
+ EditView,
21
+ IndexView,
22
+ InspectView,
23
+ )
18
24
  from wagtail.admin.viewsets.base import ViewSet, ViewSetGroup
19
25
  from wagtail.admin.viewsets.chooser import ChooserViewSet
20
26
  from wagtail.admin.viewsets.model import ModelViewSet, ModelViewSetGroup
@@ -80,6 +86,14 @@ class CustomModelEditForm(forms.ModelForm):
80
86
  fields = ("content",)
81
87
 
82
88
 
89
+ class TestCreateView(CreateView):
90
+ model = ModelWithStringTypePrimaryKey
91
+ fields = ["custom_id", "content"]
92
+ add_url_name = "testapp_generic_create"
93
+ edit_url_name = "testapp_generic_edit"
94
+ index_url_name = "testapp_generic_index"
95
+
96
+
83
97
  class TestEditView(EditView):
84
98
  model = ModelWithStringTypePrimaryKey
85
99
  context_object_name = "test_object"
@@ -232,6 +246,7 @@ class FeatureCompleteToyViewSet(ModelViewSet):
232
246
  # search_fields derived from the model
233
247
  inspect_view_enabled = True
234
248
  inspect_view_fields = ["strid", "release_date"]
249
+ sort_order_field = "sort_order"
235
250
 
236
251
  panels = [
237
252
  FieldPanel("name"),
@@ -252,7 +267,7 @@ class FCToyAlt1ViewSet(ModelViewSet):
252
267
  menu_label = "FC Toys Alt 1"
253
268
  inspect_view_class = FCToyAlt1InspectView
254
269
  inspect_view_enabled = True
255
- inspect_view_fields_exclude = ["strid", "release_date"]
270
+ inspect_view_fields_exclude = ["strid", "release_date", "sort_order"]
256
271
  copy_view_enabled = False
257
272
 
258
273
  def get_index_view_kwargs(self, **kwargs):
@@ -281,6 +296,7 @@ class ToyViewSetGroup(ModelViewSetGroup):
281
296
  exclude_form_fields=(),
282
297
  search_fields=["name"],
283
298
  search_backend_name=None,
299
+ sort_order_field=None,
284
300
  ),
285
301
  ModelViewSet(
286
302
  name="fctoy-alt3",
@@ -1,4 +1,4 @@
1
- from typing import Any, Optional
1
+ from typing import Any
2
2
  from unittest import mock
3
3
 
4
4
  from django.conf import settings
@@ -174,8 +174,8 @@ class WagtailPageTestCase(WagtailTestUtils, TestCase):
174
174
  def assertPageIsRoutable(
175
175
  self,
176
176
  page: Page,
177
- route_path: Optional[str] = "/",
178
- msg: Optional[str] = None,
177
+ route_path: str | None = "/",
178
+ msg: str | None = None,
179
179
  ):
180
180
  """
181
181
  Asserts that ``page`` can be routed to without raising a ``Http404`` error.
@@ -216,13 +216,13 @@ class WagtailPageTestCase(WagtailTestUtils, TestCase):
216
216
  def assertPageIsRenderable(
217
217
  self,
218
218
  page: Page,
219
- route_path: Optional[str] = "/",
220
- query_data: Optional[dict[str, Any]] = None,
221
- post_data: Optional[dict[str, Any]] = None,
222
- user: Optional[AbstractBaseUser] = None,
223
- accept_404: Optional[bool] = False,
224
- accept_redirect: Optional[bool] = False,
225
- msg: Optional[str] = None,
219
+ route_path: str | None = "/",
220
+ query_data: dict[str, Any] | None = None,
221
+ post_data: dict[str, Any] | None = None,
222
+ user: AbstractBaseUser | None = None,
223
+ accept_404: bool | None = False,
224
+ accept_redirect: bool | None = False,
225
+ msg: str | None = None,
226
226
  ):
227
227
  """
228
228
  Asserts that ``page`` can be rendered without raising a fatal error.
@@ -297,9 +297,9 @@ class WagtailPageTestCase(WagtailTestUtils, TestCase):
297
297
  def assertPageIsEditable(
298
298
  self,
299
299
  page: Page,
300
- post_data: Optional[dict[str, Any]] = None,
301
- user: Optional[AbstractBaseUser] = None,
302
- msg: Optional[str] = None,
300
+ post_data: dict[str, Any] | None = None,
301
+ user: AbstractBaseUser | None = None,
302
+ msg: str | None = None,
303
303
  ):
304
304
  """
305
305
  Asserts that the page edit view works for ``page`` without raising a fatal error.
@@ -378,10 +378,10 @@ class WagtailPageTestCase(WagtailTestUtils, TestCase):
378
378
  def assertPageIsPreviewable(
379
379
  self,
380
380
  page: Page,
381
- mode: Optional[str] = "",
382
- post_data: Optional[dict[str, Any]] = None,
383
- user: Optional[AbstractBaseUser] = None,
384
- msg: Optional[str] = None,
381
+ mode: str | None = "",
382
+ post_data: dict[str, Any] | None = None,
383
+ user: AbstractBaseUser | None = None,
384
+ msg: str | None = None,
385
385
  ):
386
386
  """
387
387
  Asserts that the page preview view can be loaded for ``page`` without raising a fatal error.
@@ -1,5 +1,3 @@
1
- from typing import Union
2
-
3
1
  from django.test import SimpleTestCase
4
2
 
5
3
  from .wagtail_tests import WagtailTestUtils
@@ -9,9 +7,9 @@ class AdminTemplateTestUtils:
9
7
  base_breadcrumb_items = [{"label": "Home", "url": "/admin/"}]
10
8
 
11
9
  def assertBreadcrumbsItemsRendered(
12
- self: Union[WagtailTestUtils, SimpleTestCase],
10
+ self: WagtailTestUtils | SimpleTestCase,
13
11
  items: list[dict[str, str]],
14
- html: Union[str, bytes],
12
+ html: str | bytes,
15
13
  ):
16
14
  soup = self.get_soup(html)
17
15
  # Select with a class instead of a data-controller attribute because
@@ -79,8 +77,8 @@ class AdminTemplateTestUtils:
79
77
  )
80
78
 
81
79
  def assertBreadcrumbsNotRendered(
82
- self: Union[WagtailTestUtils, SimpleTestCase],
83
- html: Union[str, bytes],
80
+ self: WagtailTestUtils | SimpleTestCase,
81
+ html: str | bytes,
84
82
  ):
85
83
  soup = self.get_soup(html)
86
84
  # Select with a class instead of a data-controller attribute because
@@ -1,6 +1,5 @@
1
1
  import warnings
2
2
  from contextlib import contextmanager
3
- from typing import Union
4
3
 
5
4
  from bs4 import BeautifulSoup
6
5
  from django.contrib.auth import get_user_model
@@ -9,7 +8,7 @@ from django.test.testcases import assert_and_parse_html
9
8
 
10
9
  class WagtailTestUtils:
11
10
  @staticmethod
12
- def get_soup(markup: Union[str, bytes]) -> BeautifulSoup:
11
+ def get_soup(markup: str | bytes) -> BeautifulSoup:
13
12
  # Use an empty string_containers argument so that <script>, <style>, and
14
13
  # <template> tags do not have their text ignored.
15
14
  return BeautifulSoup(markup, "html.parser", string_containers={})
@@ -2366,6 +2366,21 @@ class TestStructBlock(SimpleTestCase):
2366
2366
 
2367
2367
  self.assertIs(js_args[2]["collapsed"], case)
2368
2368
 
2369
+ def test_adapt_label_format(self):
2370
+ class LinkBlock(blocks.StructBlock):
2371
+ title = blocks.CharBlock()
2372
+ link = blocks.URLBlock()
2373
+
2374
+ cases = [None, "", "{title} ({link})"]
2375
+ for case in cases:
2376
+ with self.subTest(label_format=case):
2377
+ block = LinkBlock(label_format=case)
2378
+
2379
+ block.set_name("test_structblock")
2380
+ js_args = StructBlockAdapter().js_args(block)
2381
+
2382
+ self.assertEqual(js_args[2].get("labelFormat"), case)
2383
+
2369
2384
  def test_searchable_content(self):
2370
2385
  class LinkBlock(blocks.StructBlock):
2371
2386
  title = blocks.CharBlock()
@@ -3,6 +3,7 @@ import json
3
3
  import unittest
4
4
  from unittest.mock import Mock
5
5
 
6
+ from asgiref.sync import async_to_sync
6
7
  from django.conf import settings
7
8
  from django.contrib.auth import get_user_model
8
9
  from django.contrib.auth.models import AnonymousUser, Group
@@ -196,6 +197,20 @@ class TestValidation(TestCase):
196
197
  self.assertEqual(retrieved_page.draft_title, "Hello world edited")
197
198
 
198
199
 
200
+ class TestAsyncMethods(TestCase):
201
+ def test_asave_with_update_fields_none_saves_all_fields(self):
202
+ root = Page.get_first_root_node()
203
+ page = Page(title="Original title", slug="async-page")
204
+ root.add_child(instance=page)
205
+
206
+ # Call asave using async_to_sync
207
+ page.title = "Updated title"
208
+ async_to_sync(page.asave)()
209
+
210
+ refreshed = Page.objects.get(id=page.id)
211
+ assert refreshed.title == "Updated title"
212
+
213
+
199
214
  @override_settings(
200
215
  ALLOWED_HOSTS=[
201
216
  "localhost",
@@ -1,14 +1,41 @@
1
+ from unittest import mock
2
+
1
3
  from django.conf import settings
2
4
  from django.db.models import F
3
- from django.test import TestCase
5
+ from django.test import TestCase, override_settings
4
6
 
5
7
  from wagtail.models import Page
8
+ from wagtail.search import index
6
9
  from wagtail.search.backends import get_search_backend
7
10
  from wagtail.search.backends.base import (
8
11
  BaseSearchQueryCompiler,
9
12
  BaseSearchResults,
10
13
  OrderByFieldError,
11
14
  )
15
+ from wagtail.test.testapp.models import SimplePage
16
+ from wagtail.test.utils import WagtailTestUtils
17
+
18
+
19
+ @mock.patch("wagtail.tests.DummySearchBackend", create=True)
20
+ @override_settings(
21
+ WAGTAILSEARCH_BACKENDS={"default": {"BACKEND": "wagtail.tests.DummySearchBackend"}}
22
+ )
23
+ class TestInsertOrUpdateObject(WagtailTestUtils, TestCase):
24
+ def test_converts_to_specific_page(self, backend):
25
+ root_page = Page.objects.get(id=1)
26
+ page = root_page.add_child(
27
+ instance=SimplePage(title="test", slug="test", content="test")
28
+ )
29
+
30
+ # Convert page into a generic "Page" object and add it into the index
31
+ unspecific_page = page.page_ptr
32
+
33
+ backend().reset_mock()
34
+
35
+ index.insert_or_update_object(unspecific_page)
36
+
37
+ # It should be automatically converted back to the specific version
38
+ backend().add.assert_called_with(page)
12
39
 
13
40
 
14
41
  class PageSearchTests:
@@ -55,7 +82,7 @@ class PageSearchTests:
55
82
  "blah", order_by_relevance=False, backend=self.backend_name
56
83
  )
57
84
  self.assertIn(
58
- 'Cannot sort search results with "OrderBy(F(last_published_at), descending=False)".',
85
+ 'Sorting search results with "OrderBy(F(last_published_at), descending=False)" is not supported by this search backend.',
59
86
  str(ctx.exception),
60
87
  )
61
88
 
@@ -0,0 +1,69 @@
1
+ from contextlib import contextmanager
2
+
3
+ from django.core import checks
4
+ from django.test import TestCase
5
+
6
+ from wagtail.models import Page
7
+ from wagtail.test.testapp.models import (
8
+ TaggedChildPage,
9
+ TaggedGrandchildPage,
10
+ TaggedPage,
11
+ )
12
+
13
+
14
+ @contextmanager
15
+ def patch_search_fields(model, new_search_fields):
16
+ """
17
+ A context manager to allow testing of different search_fields configurations
18
+ without permanently changing the models' search_fields.
19
+ """
20
+ old_search_fields = model.search_fields
21
+ model.search_fields = new_search_fields
22
+ yield
23
+ model.search_fields = old_search_fields
24
+
25
+
26
+ class TestSearchFields(TestCase):
27
+ def test_checking_core_page_fields_are_indexed(self):
28
+ """Run checks to ensure that when core page fields are missing we get a warning"""
29
+
30
+ # first confirm that errors show as TaggedPage (in test models) has no Page.search_fields
31
+ errors = [
32
+ error for error in checks.run_checks() if error.id == "wagtailsearch.W001"
33
+ ]
34
+
35
+ # should only ever get this warning on the sub-classes of the page model
36
+ self.assertEqual(
37
+ [TaggedPage, TaggedChildPage, TaggedGrandchildPage],
38
+ [error.obj for error in errors],
39
+ )
40
+
41
+ for error in errors:
42
+ self.assertEqual(
43
+ error.msg,
44
+ "Core Page fields missing in `search_fields`",
45
+ )
46
+ self.assertIn(
47
+ "Page model search fields `search_fields = Page.search_fields + [...]`",
48
+ error.hint,
49
+ )
50
+
51
+ # second check that we get no errors when setting up the models correctly
52
+ with patch_search_fields(
53
+ TaggedPage, Page.search_fields + TaggedPage.search_fields
54
+ ):
55
+ errors = [
56
+ error
57
+ for error in checks.run_checks()
58
+ if error.id == "wagtailsearch.W001"
59
+ ]
60
+ self.assertEqual([], errors)
61
+
62
+ # third check that we get no errors when disabling all model search
63
+ with patch_search_fields(TaggedPage, []):
64
+ errors = [
65
+ error
66
+ for error in checks.run_checks()
67
+ if error.id == "wagtailsearch.W001"
68
+ ]
69
+ self.assertEqual([], errors)
@@ -4,12 +4,13 @@ import unittest
4
4
  from django.conf import settings
5
5
  from django.core.exceptions import ImproperlyConfigured
6
6
  from django.core.files.uploadedfile import SimpleUploadedFile
7
- from django.template import Context, Template
8
- from django.test import TestCase
7
+ from django.template import Context, Origin, Template
8
+ from django.test import SimpleTestCase, TestCase
9
9
 
10
10
  from wagtail.admin.tests.test_contentstate import content_state_equal
11
11
  from wagtail.models import PAGE_MODEL_CLASSES, Page, Site
12
12
  from wagtail.test.dummy_external_storage import DummyExternalStorage
13
+ from wagtail.test.numberformat import ignore_numberformat
13
14
  from wagtail.test.testapp.models import (
14
15
  BusinessChild,
15
16
  BusinessIndex,
@@ -470,12 +471,67 @@ class TestDummyExternalStorage(WagtailTestUtils, TestCase):
470
471
  settings.WAGTAIL_CHECK_TEMPLATE_NUMBER_FORMAT,
471
472
  "Number formatting functions have not been patched",
472
473
  )
473
- class TestPatchedNumberFormat(TestCase):
474
+ class TestPatchedNumberFormat(SimpleTestCase):
474
475
  def test_outputting_number_directly_is_disallowed(self):
475
476
  context = Context({"num": 42})
476
- template = Template("the answer is {{ num }}")
477
- with self.assertRaises(ImproperlyConfigured):
478
- template.render(context)
477
+ template_name = "wagtailcore/tests/some_template.html"
478
+ external_template_name = "external_package/other_template.html"
479
+ templates = [
480
+ Template("the answer is {{ num }}"),
481
+ Template(
482
+ "the answer is {{ num }}",
483
+ origin=Origin(
484
+ name=f"/some/path/{template_name}",
485
+ template_name=template_name,
486
+ ),
487
+ ),
488
+ Template(
489
+ "the answer is {{ num }}",
490
+ origin=Origin(
491
+ name=f"/some/path/{external_template_name}",
492
+ template_name=external_template_name,
493
+ ),
494
+ ),
495
+ ]
496
+ for template in templates:
497
+ with (
498
+ self.subTest(template=template),
499
+ self.assertRaises(ImproperlyConfigured),
500
+ ):
501
+ template.render(context)
502
+
503
+ def test_ignore_numberformat(self):
504
+ context = Context({"num": 4815162342})
505
+ template_name = "external_package/some_template.html"
506
+ with ignore_numberformat([template_name]):
507
+ ignored_template = Template(
508
+ "the answer is {{ num }}",
509
+ origin=Origin(
510
+ name=f"/some/path/{template_name}",
511
+ template_name=template_name,
512
+ ),
513
+ )
514
+
515
+ self.assertEqual(
516
+ ignored_template.render(context),
517
+ "the answer is 4815162342",
518
+ )
519
+ with self.settings(USE_THOUSAND_SEPARATOR=True):
520
+ self.assertEqual(
521
+ ignored_template.render(context),
522
+ "the answer is 4,815,162,342",
523
+ )
524
+
525
+ # But other templates should still raise
526
+ other_template = Template(
527
+ "the answer is {{ num }}",
528
+ origin=Origin(
529
+ name="/some/path/important/tests/some_template.html",
530
+ template_name="important/tests/some_template.html",
531
+ ),
532
+ )
533
+ with self.assertRaises(ImproperlyConfigured):
534
+ other_template.render(context)
479
535
 
480
536
  def test_outputting_number_via_intcomma(self):
481
537
  context = Context({"num": 9000})
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ from unittest import mock
2
3
 
3
4
  from django.conf import settings
4
5
  from django.contrib.auth import get_user_model
@@ -21,7 +22,12 @@ from wagtail.models import (
21
22
  WorkflowState,
22
23
  WorkflowTask,
23
24
  )
24
- from wagtail.test.testapp.models import FullFeaturedSnippet, ModeratedModel, SimplePage
25
+ from wagtail.test.testapp.models import (
26
+ FullFeaturedSnippet,
27
+ ModeratedModel,
28
+ SimplePage,
29
+ SimpleTask,
30
+ )
25
31
  from wagtail.test.utils.wagtail_tests import WagtailTestUtils
26
32
 
27
33
 
@@ -117,6 +123,24 @@ class TestWorkflowModels(TestCase):
117
123
  self.assertTrue(workflow_2.all_pages().filter(id=hello_page.id).exists())
118
124
  self.assertTrue(workflow_2.all_pages().filter(id=goodbye_page.id).exists())
119
125
 
126
+ def test_specific_gracefully_handles_missing_rows(self):
127
+ # 13376 - Check that .specific handles missing rows for Tasks
128
+ # when generating warnings
129
+
130
+ # Trick SpecificIteraterable.__init__() into always looking for SimpleTasks
131
+ with mock.patch(
132
+ "wagtail.query.ContentType.objects.get_for_id",
133
+ return_value=ContentType.objects.get_for_model(SimpleTask),
134
+ ):
135
+ with self.assertWarnsRegex(
136
+ RuntimeWarning,
137
+ "Specific versions of the following items could not be found",
138
+ ):
139
+ tasks = list(Task.objects.all().specific())
140
+
141
+ # Missing tasks should be supplemented with generic tasks
142
+ self.assertEqual(tasks, [Task.objects.get(name="Moderators approval")])
143
+
120
144
 
121
145
  class TestPageWorkflows(WagtailTestUtils, TestCase):
122
146
  fixtures = ["test.json"]
@@ -127,6 +127,9 @@ msgstr "Tmavé"
127
127
  msgid "Default"
128
128
  msgstr "Default(ní)"
129
129
 
130
+ msgid "Keyboard shortcuts"
131
+ msgstr "Klávesové zkratky"
132
+
130
133
  msgid "user profile"
131
134
  msgstr "uživatelský profile"
132
135
 
@@ -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: 2025-07-24 16:20+0200\n"
11
+ "POT-Creation-Date: 2025-10-23 16:45+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"
@@ -379,7 +379,7 @@ msgid "Account"
379
379
  msgstr ""
380
380
 
381
381
  #: templates/wagtailusers/users/create.html:11
382
- #: templates/wagtailusers/users/create.html:44
382
+ #: templates/wagtailusers/users/create.html:45
383
383
  #: templates/wagtailusers/users/edit.html:11
384
384
  msgid "Roles"
385
385
  msgstr ""
@@ -8,7 +8,7 @@
8
8
  # Joeri Vlekken, 2024
9
9
  # Kees Hink <keeshink@gmail.com>, 2017
10
10
  # Maarten Kling <kling.maarten@gmail.com>, 2023
11
- # Storm Heg <storm@stormbase.digital>, 2021-2024
11
+ # Storm Heg <storm@stormbase.digital>, 2021-2025
12
12
  # Thijs Kramer <thijskramer@gmail.com>, 2015
13
13
  # Thijs Kramer <thijskramer@gmail.com>, 2015-2016,2022-2023
14
14
  msgid ""
@@ -17,7 +17,7 @@ msgstr ""
17
17
  "Report-Msgid-Bugs-To: \n"
18
18
  "POT-Creation-Date: 2025-07-24 16:20+0200\n"
19
19
  "PO-Revision-Date: 2014-02-19 11:54+0000\n"
20
- "Last-Translator: Thijs Kramer <thijskramer@gmail.com>, 2015-2016,2022-2023\n"
20
+ "Last-Translator: Storm Heg <storm@stormbase.digital>, 2021-2025\n"
21
21
  "Language-Team: Dutch (http://app.transifex.com/torchbox/wagtail/language/"
22
22
  "nl/)\n"
23
23
  "MIME-Version: 1.0\n"
@@ -154,6 +154,9 @@ msgstr "informatiedichtheid"
154
154
  msgid "Keyboard shortcuts"
155
155
  msgstr "Sneltoetsen"
156
156
 
157
+ msgid "Enable custom keyboard shortcuts specific to Wagtail."
158
+ msgstr "Schakel sneltoetsen voor gebruik met Wagtail in."
159
+
157
160
  msgid "user profile"
158
161
  msgstr "gebruikersprofiel"
159
162
 
@@ -263,7 +266,7 @@ msgid "Change"
263
266
  msgstr "Wijzigen"
264
267
 
265
268
  msgid "Custom permissions"
266
- msgstr "Aangepaste machtigingen"
269
+ msgstr "Speciale machtigingen"
267
270
 
268
271
  msgid "Toggle all"
269
272
  msgstr "Toon/verberg alle"
@@ -20,6 +20,7 @@
20
20
  # sergeybe <sergeybe@gmail.com>, 2020
21
21
  # Sergey Komarov <sjkomarov@gmail.com>, 2014
22
22
  # Tatsiana Tsygan <art.tatsiana@gmail.com>, 2018
23
+ # Twixxik, 2025
23
24
  # Vassily <zuber.kg@gmail.com>, 2017
24
25
  # Vassily <zuber.kg@gmail.com>, 2017
25
26
  # Влад <integration.into.society@gmail.com>, 2022
@@ -34,7 +35,7 @@ msgstr ""
34
35
  "Report-Msgid-Bugs-To: \n"
35
36
  "POT-Creation-Date: 2025-07-24 16:20+0200\n"
36
37
  "PO-Revision-Date: 2014-02-19 11:54+0000\n"
37
- "Last-Translator: Никита Викторович <hnknta@gmail.com>, 2014\n"
38
+ "Last-Translator: Twixxik, 2025\n"
38
39
  "Language-Team: Russian (http://app.transifex.com/torchbox/wagtail/language/"
39
40
  "ru/)\n"
40
41
  "MIME-Version: 1.0\n"
@@ -172,6 +173,9 @@ msgstr "плотность"
172
173
  msgid "Keyboard shortcuts"
173
174
  msgstr "Горячие клавиши"
174
175
 
176
+ msgid "Enable custom keyboard shortcuts specific to Wagtail."
177
+ msgstr "Включить пользовательские сочетания клавиш для Wagtail."
178
+
175
179
  msgid "user profile"
176
180
  msgstr "профиль пользователя"
177
181