wagtail 6.0.2__py3-none-any.whl → 6.1rc1__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 (355) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/admin/checks.py +51 -0
  3. wagtail/admin/compare.py +1 -1
  4. wagtail/admin/filters.py +70 -1
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/forms/collections.py +15 -0
  7. wagtail/admin/forms/pages.py +49 -0
  8. wagtail/admin/locale/de/LC_MESSAGES/django.mo +0 -0
  9. wagtail/admin/locale/de/LC_MESSAGES/django.po +5 -5
  10. wagtail/admin/locale/en/LC_MESSAGES/django.po +474 -385
  11. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +3 -3
  12. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  13. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +73 -2
  14. wagtail/admin/locale/ro/LC_MESSAGES/django.mo +0 -0
  15. wagtail/admin/locale/ro/LC_MESSAGES/django.po +3 -3
  16. wagtail/admin/panels/comment_panel.py +1 -1
  17. wagtail/admin/panels/field_panel.py +1 -1
  18. wagtail/admin/rich_text/converters/editor_html.py +3 -1
  19. wagtail/admin/rich_text/editors/draftail/__init__.py +28 -2
  20. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  21. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  22. wagtail/admin/static/wagtailadmin/images/favicon.ico +0 -0
  23. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  24. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  25. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  28. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -1
  30. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  31. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/preview-panel.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  40. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  42. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  48. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +4 -4
  49. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  51. wagtail/admin/staticfiles.py +1 -0
  52. wagtail/admin/templates/wagtailadmin/base.html +1 -0
  53. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +3 -1
  54. wagtail/admin/templates/wagtailadmin/collections/index_results.html +10 -0
  55. wagtail/admin/templates/wagtailadmin/generic/base.html +1 -9
  56. wagtail/admin/templates/wagtailadmin/generic/form.html +3 -2
  57. wagtail/admin/templates/wagtailadmin/generic/history/action_cell.html +27 -0
  58. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +3 -3
  59. wagtail/admin/templates/wagtailadmin/icons/keyboard.svg +1 -0
  60. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +3 -1
  61. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -14
  62. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +3 -1
  63. wagtail/admin/templates/wagtailadmin/pages/choose_parent.html +17 -0
  64. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +8 -0
  65. wagtail/admin/templates/wagtailadmin/pages/history.html +1 -61
  66. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -3
  67. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +2 -2
  68. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +25 -27
  69. wagtail/admin/templates/wagtailadmin/pages/page_listing_header.html +2 -1
  70. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  71. wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html +3 -1
  72. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +1 -1
  73. wagtail/admin/templates/wagtailadmin/shared/active_filters.html +2 -1
  74. wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +8 -0
  75. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  76. wagtail/admin/templates/wagtailadmin/shared/headers/page_edit_header.html +1 -1
  77. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +21 -9
  78. wagtail/admin/templates/wagtailadmin/shared/human_readable_date.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +29 -0
  80. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +2 -1
  81. wagtail/admin/templates/wagtailadmin/skeleton.html +2 -1
  82. wagtail/admin/templates/wagtailadmin/tables/related_objects_cell.html +9 -0
  83. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +9 -7
  84. wagtail/admin/templates/wagtailadmin/widgets/draftail_rich_text_area.html +1 -1
  85. wagtail/admin/templates/wagtailadmin/workflows/create.html +6 -23
  86. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +6 -15
  87. wagtail/admin/templates/wagtailadmin/workflows/edit.html +6 -23
  88. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +6 -13
  89. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -4
  90. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +18 -0
  91. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_title_cell.html +7 -0
  92. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +25 -0
  93. wagtail/admin/templates/wagtailadmin/workflows/index.html +0 -99
  94. wagtail/admin/templates/wagtailadmin/workflows/index_results.html +10 -0
  95. wagtail/admin/templates/wagtailadmin/workflows/task_index.html +0 -30
  96. wagtail/admin/templates/wagtailadmin/workflows/task_index_results.html +10 -0
  97. wagtail/admin/templates/wagtailadmin/workflows/usage.html +1 -1
  98. wagtail/admin/templatetags/wagtailadmin_tags.py +116 -39
  99. wagtail/admin/tests/pages/test_create_page.py +10 -4
  100. wagtail/admin/tests/pages/test_custom_listing.py +37 -0
  101. wagtail/admin/tests/pages/test_edit_page.py +6 -6
  102. wagtail/admin/tests/pages/test_explorer_view.py +19 -18
  103. wagtail/admin/tests/pages/test_move_page.py +1 -1
  104. wagtail/admin/tests/pages/test_page_usage.py +50 -2
  105. wagtail/admin/tests/pages/test_parent_page_chooser_view.py +119 -0
  106. wagtail/admin/tests/pages/test_preview.py +18 -4
  107. wagtail/admin/tests/test_account_management.py +20 -1
  108. wagtail/admin/tests/test_audit_log.py +172 -5
  109. wagtail/admin/tests/test_checks.py +92 -0
  110. wagtail/admin/tests/test_collections_views.py +19 -5
  111. wagtail/admin/tests/test_compare.py +6 -6
  112. wagtail/admin/tests/test_dashboard.py +404 -0
  113. wagtail/admin/tests/test_dbwhitelister.py +4 -5
  114. wagtail/admin/tests/test_edit_handlers.py +2 -2
  115. wagtail/admin/tests/test_keyboard_shortcuts.py +84 -0
  116. wagtail/admin/tests/test_page_chooser.py +31 -18
  117. wagtail/admin/tests/test_privacy.py +36 -2
  118. wagtail/admin/tests/test_rich_text.py +168 -23
  119. wagtail/admin/tests/test_templatetags.py +411 -43
  120. wagtail/admin/tests/test_views.py +4 -2
  121. wagtail/admin/tests/test_workflows.py +531 -9
  122. wagtail/admin/tests/tests.py +3 -1
  123. wagtail/admin/tests/ui/test_tables.py +48 -1
  124. wagtail/admin/tests/viewsets/test_model_viewset.py +126 -29
  125. wagtail/admin/ui/side_panels.py +3 -1
  126. wagtail/admin/ui/tables/__init__.py +13 -1
  127. wagtail/admin/ui/tables/pages.py +17 -6
  128. wagtail/admin/urls/__init__.py +8 -3
  129. wagtail/admin/urls/pages.py +5 -0
  130. wagtail/admin/urls/workflows.py +10 -0
  131. wagtail/admin/views/chooser.py +20 -24
  132. wagtail/admin/views/collections.py +17 -1
  133. wagtail/admin/views/generic/base.py +31 -4
  134. wagtail/admin/views/generic/history.py +220 -51
  135. wagtail/admin/views/generic/mixins.py +7 -4
  136. wagtail/admin/views/generic/models.py +54 -38
  137. wagtail/admin/views/generic/multiple_upload.py +17 -8
  138. wagtail/admin/views/generic/usage.py +17 -11
  139. wagtail/admin/views/home.py +15 -12
  140. wagtail/admin/views/mixins.py +30 -0
  141. wagtail/admin/views/pages/choose_parent.py +73 -0
  142. wagtail/admin/views/pages/history.py +54 -66
  143. wagtail/admin/views/pages/listing.py +187 -106
  144. wagtail/admin/views/pages/usage.py +6 -1
  145. wagtail/admin/views/pages/utils.py +70 -1
  146. wagtail/admin/views/workflows.py +150 -21
  147. wagtail/admin/viewsets/model.py +2 -2
  148. wagtail/admin/viewsets/pages.py +77 -0
  149. wagtail/admin/wagtail_hooks.py +40 -2
  150. wagtail/admin/widgets/button.py +10 -9
  151. wagtail/api/v2/filters.py +1 -1
  152. wagtail/api/v2/tests/test_pages.py +1 -1
  153. wagtail/blocks/base.py +18 -9
  154. wagtail/blocks/field_block.py +9 -7
  155. wagtail/blocks/list_block.py +16 -6
  156. wagtail/blocks/static_block.py +3 -0
  157. wagtail/blocks/stream_block.py +58 -23
  158. wagtail/blocks/struct_block.py +15 -9
  159. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +39 -47
  160. wagtail/contrib/forms/models.py +5 -5
  161. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +44 -33
  162. wagtail/contrib/forms/templates/wagtailforms/submissions_index.html +2 -63
  163. wagtail/contrib/forms/tests/test_models.py +26 -0
  164. wagtail/contrib/forms/urls.py +6 -0
  165. wagtail/contrib/forms/views.py +52 -49
  166. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.mo +0 -0
  167. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +3 -3
  168. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +34 -42
  169. wagtail/contrib/redirects/signal_handlers.py +1 -1
  170. wagtail/contrib/redirects/templates/wagtailredirects/index.html +1 -36
  171. wagtail/contrib/redirects/templates/wagtailredirects/index_results.html +18 -0
  172. wagtail/contrib/redirects/templates/wagtailredirects/redirect_target_cell.html +8 -0
  173. wagtail/contrib/redirects/tests/test_import_command.py +1 -1
  174. wagtail/contrib/redirects/tests/test_redirects.py +79 -8
  175. wagtail/contrib/redirects/urls.py +2 -1
  176. wagtail/contrib/redirects/views.py +85 -55
  177. wagtail/contrib/search_promotions/admin_urls.py +2 -1
  178. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +41 -64
  179. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +1 -16
  180. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index_results.html +11 -0
  181. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/list.html +0 -51
  182. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/results.html +3 -16
  183. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/search_promotion_column.html +15 -0
  184. wagtail/contrib/search_promotions/tests.py +122 -9
  185. wagtail/contrib/search_promotions/views.py +66 -65
  186. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
  187. wagtail/contrib/settings/registry.py +10 -5
  188. wagtail/contrib/settings/tests/generic/test_admin.py +9 -0
  189. wagtail/contrib/settings/tests/site_specific/test_admin.py +10 -1
  190. wagtail/contrib/settings/tests/site_specific/test_model.py +3 -3
  191. wagtail/contrib/settings/tests/site_specific/test_templates.py +1 -1
  192. wagtail/contrib/settings/views.py +3 -1
  193. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  194. wagtail/contrib/simple_translation/tests/test_wagtail_hooks.py +2 -2
  195. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  196. wagtail/contrib/table_block/blocks.py +1 -1
  197. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  198. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  199. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  200. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  201. wagtail/coreutils.py +3 -2
  202. wagtail/documents/admin_urls.py +2 -2
  203. wagtail/documents/locale/en/LC_MESSAGES/django.po +22 -22
  204. wagtail/documents/migrations/0013_delete_uploadeddocument.py +16 -0
  205. wagtail/documents/models.py +1 -20
  206. wagtail/documents/rich_text/__init__.py +11 -7
  207. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  208. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  209. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  210. wagtail/documents/templates/wagtaildocs/documents/index.html +0 -16
  211. wagtail/documents/tests/test_admin_views.py +155 -23
  212. wagtail/documents/tests/test_collection_privacy.py +55 -1
  213. wagtail/documents/tests/test_rich_text.py +14 -0
  214. wagtail/documents/views/documents.py +25 -22
  215. wagtail/documents/views/multiple.py +6 -7
  216. wagtail/documents/views/serve.py +16 -1
  217. wagtail/documents/wagtail_hooks.py +20 -15
  218. wagtail/embeds/blocks.py +5 -0
  219. wagtail/embeds/locale/en/LC_MESSAGES/django.po +2 -2
  220. wagtail/embeds/rich_text/__init__.py +1 -1
  221. wagtail/embeds/tests/test_rich_text.py +14 -0
  222. wagtail/embeds/wagtail_hooks.py +4 -14
  223. wagtail/fields.py +3 -48
  224. wagtail/images/admin_urls.py +2 -2
  225. wagtail/images/check_files/wagtail.jpg +0 -0
  226. wagtail/images/check_files/wagtail.png +0 -0
  227. wagtail/images/fields.py +2 -0
  228. wagtail/images/image_operations.py +1 -1
  229. wagtail/images/locale/en/LC_MESSAGES/django.po +33 -45
  230. wagtail/images/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  231. wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +4 -0
  232. wagtail/images/migrations/0026_delete_uploadedimage.py +16 -0
  233. wagtail/images/models.py +49 -43
  234. wagtail/images/rich_text/__init__.py +18 -8
  235. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  236. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  237. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  238. wagtail/images/templates/wagtailimages/images/image_listing_header.html +6 -0
  239. wagtail/images/templates/wagtailimages/images/index.html +11 -51
  240. wagtail/images/tests/test_admin_views.py +119 -62
  241. wagtail/images/tests/test_image_operations.py +10 -0
  242. wagtail/images/tests/test_models.py +35 -33
  243. wagtail/images/tests/test_rich_text.py +14 -0
  244. wagtail/images/tests/utils.py +1 -1
  245. wagtail/images/views/images.py +35 -64
  246. wagtail/images/views/multiple.py +6 -7
  247. wagtail/images/wagtail_hooks.py +4 -14
  248. wagtail/locale/en/LC_MESSAGES/django.po +150 -136
  249. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  250. wagtail/locales/tests.py +18 -3
  251. wagtail/locales/views.py +0 -1
  252. wagtail/management/commands/rebuild_references_index.py +3 -1
  253. wagtail/migrations/0092_alter_collectionviewrestriction_password_and_more.py +33 -0
  254. wagtail/migrations/0093_uploadedfile.py +53 -0
  255. wagtail/models/__init__.py +147 -32
  256. wagtail/models/i18n.py +1 -1
  257. wagtail/models/{collections.py → media.py} +33 -2
  258. wagtail/models/reference_index.py +1 -1
  259. wagtail/models/view_restrictions.py +10 -3
  260. wagtail/project_template/project_name/settings/base.py +6 -0
  261. wagtail/project_template/requirements.txt +1 -1
  262. wagtail/rich_text/__init__.py +25 -8
  263. wagtail/rich_text/pages.py +19 -8
  264. wagtail/rich_text/rewriters.py +140 -68
  265. wagtail/search/backends/database/mysql/mysql.py +3 -3
  266. wagtail/search/backends/database/postgres/postgres.py +3 -3
  267. wagtail/search/backends/database/sqlite/sqlite.py +2 -2
  268. wagtail/search/backends/elasticsearch7.py +4 -0
  269. wagtail/search/locale/en/LC_MESSAGES/django.po +3 -3
  270. wagtail/search/tests/test_postgres_backend.py +50 -0
  271. wagtail/sites/locale/en/LC_MESSAGES/django.po +8 -8
  272. wagtail/sites/tests.py +35 -9
  273. wagtail/sites/views.py +3 -1
  274. wagtail/snippets/locale/de/LC_MESSAGES/django.mo +0 -0
  275. wagtail/snippets/locale/de/LC_MESSAGES/django.po +5 -6
  276. wagtail/snippets/locale/en/LC_MESSAGES/django.po +16 -56
  277. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  278. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  279. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +3 -1
  280. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +3 -1
  281. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -1
  282. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -1
  283. wagtail/snippets/tests/test_preview.py +13 -2
  284. wagtail/snippets/tests/test_snippets.py +41 -16
  285. wagtail/snippets/tests/test_viewset.py +63 -18
  286. wagtail/snippets/tests/test_workflows.py +12 -0
  287. wagtail/snippets/views/snippets.py +1 -40
  288. wagtail/templatetags/wagtailcore_tags.py +1 -1
  289. wagtail/test/demosite/models.py +1 -1
  290. wagtail/test/middleware.py +14 -1
  291. wagtail/test/testapp/fixtures/test.json +20 -0
  292. wagtail/test/testapp/migrations/0001_squashed_0073_revisablechildmodel_secret_text.py +8 -8
  293. wagtail/test/testapp/migrations/0023_snippetchoosermodel_full_featured.py +1 -0
  294. wagtail/test/testapp/migrations/0034_custompermissionmodel.py +44 -0
  295. wagtail/test/testapp/migrations/0035_modelwithcustommanager.py +30 -0
  296. wagtail/test/testapp/migrations/0036_complexdefaultstreampage.py +28 -0
  297. wagtail/test/testapp/models.py +79 -2
  298. wagtail/test/testapp/templates/tests/custom_docs_password_required.html +10 -0
  299. wagtail/test/testapp/templates/tests/custom_page_password_required.html +10 -0
  300. wagtail/test/testapp/views.py +24 -2
  301. wagtail/test/testapp/wagtail_hooks.py +19 -0
  302. wagtail/test/utils/wagtail_tests.py +2 -2
  303. wagtail/tests/test_blocks.py +262 -1
  304. wagtail/tests/test_migrations.py +1 -1
  305. wagtail/tests/test_page_model.py +77 -0
  306. wagtail/tests/test_page_privacy.py +18 -1
  307. wagtail/tests/test_rich_text.py +95 -5
  308. wagtail/tests/test_streamfield.py +43 -0
  309. wagtail/tests/test_utils.py +8 -2
  310. wagtail/tests/test_views.py +52 -1
  311. wagtail/tests/test_whitelist.py +7 -7
  312. wagtail/users/forms.py +3 -1
  313. wagtail/users/locale/en/LC_MESSAGES/django.po +124 -96
  314. wagtail/users/migrations/0013_userprofile_density.py +23 -0
  315. wagtail/users/models.py +14 -3
  316. wagtail/users/templates/wagtailusers/groups/create.html +1 -7
  317. wagtail/users/templates/wagtailusers/groups/edit.html +1 -13
  318. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +46 -2
  319. wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -2
  320. wagtail/users/templates/wagtailusers/users/create.html +1 -9
  321. wagtail/users/templates/wagtailusers/users/edit.html +1 -9
  322. wagtail/users/templates/wagtailusers/users/index.html +2 -5
  323. wagtail/users/templates/wagtailusers/users/index_results.html +3 -13
  324. wagtail/users/templates/wagtailusers/users/user_cell.html +9 -0
  325. wagtail/users/templatetags/wagtailusers_tags.py +107 -20
  326. wagtail/users/tests/test_admin_views.py +669 -90
  327. wagtail/users/views/groups.py +58 -61
  328. wagtail/users/views/users.py +211 -92
  329. wagtail/users/wagtail_hooks.py +6 -38
  330. wagtail/users/widgets.py +3 -5
  331. wagtail/utils/text.py +1 -1
  332. wagtail/views.py +5 -9
  333. wagtail/whitelist.py +1 -1
  334. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/METADATA +4 -5
  335. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/RECORD +339 -320
  336. wagtail/admin/static/wagtailadmin/js/page-editor.js +0 -1
  337. wagtail/admin/static/wagtailadmin/js/vendor/mousetrap.min.js +0 -1
  338. wagtail/admin/static/wagtailadmin/js/vendor/urlify.js +0 -1
  339. wagtail/admin/static/wagtailadmin/js/vendor/xregexp.min.js +0 -1
  340. wagtail/admin/templates/wagtailadmin/collections/index.html +0 -34
  341. wagtail/admin/templates/wagtailadmin/pages/revisions/_actions.html +0 -22
  342. wagtail/admin/templates/wagtailadmin/shared/page_breadcrumbs.html +0 -55
  343. wagtail/admin/tests/pages/test_dashboard.py +0 -172
  344. wagtail/contrib/redirects/templates/wagtailredirects/results.html +0 -23
  345. wagtail/documents/templates/wagtaildocs/documents/list.html +0 -2
  346. wagtail/search/tests/test_postgres_stemming.py +0 -40
  347. wagtail/sites/templates/wagtailsites/create.html +0 -6
  348. wagtail/sites/templates/wagtailsites/edit.html +0 -6
  349. wagtail/snippets/templates/wagtailsnippets/snippets/revisions/_actions.html +0 -36
  350. wagtail/users/templates/wagtailusers/users/list.html +0 -62
  351. wagtail/users/urls/users.py +0 -12
  352. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/LICENSE +0 -0
  353. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/WHEEL +0 -0
  354. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/entry_points.txt +0 -0
  355. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  import os.path
2
2
 
3
+ from django.contrib.contenttypes.models import ContentType
3
4
  from django.core.exceptions import PermissionDenied
4
5
  from django.http import HttpResponseBadRequest, JsonResponse
5
6
  from django.shortcuts import get_object_or_404
@@ -10,13 +11,13 @@ from django.views.decorators.vary import vary_on_headers
10
11
  from django.views.generic.base import TemplateView, View
11
12
 
12
13
  from wagtail.admin.views.generic import PermissionCheckedMixin
14
+ from wagtail.models import UploadedFile
13
15
 
14
16
 
15
17
  class AddView(PermissionCheckedMixin, TemplateView):
16
18
  # subclasses need to provide:
17
19
  # - permission_policy
18
20
  # - template_name
19
- # - upload_model
20
21
 
21
22
  # - edit_object_url_name
22
23
  # - delete_object_url_name
@@ -152,10 +153,12 @@ class AddView(PermissionCheckedMixin, TemplateView):
152
153
  return JsonResponse(self.get_invalid_response_data(form))
153
154
  else:
154
155
  # Some other field of the form has failed validation, e.g. a required metadata field
155
- # on a custom image model. Store the object as an upload_model instance instead and
156
+ # on a custom image model. Store the object as an UploadedFile instance instead and
156
157
  # present the edit form so that it will become a proper object when successfully filled in
157
- self.upload_object = self.upload_model.objects.create(
158
- file=self.request.FILES["files[]"], uploaded_by_user=self.request.user
158
+ self.upload_object = UploadedFile.objects.create(
159
+ for_content_type=ContentType.objects.get_for_model(self.get_model()),
160
+ file=self.request.FILES["files[]"],
161
+ uploaded_by_user=self.request.user,
159
162
  )
160
163
  self.object = self.model(
161
164
  title=self.request.FILES["files[]"].name,
@@ -297,7 +300,6 @@ class CreateFromUploadView(View):
297
300
  # subclasses need to provide:
298
301
  # - edit_upload_url_name
299
302
  # - delete_upload_url_name
300
- # - upload_model
301
303
  # - upload_pk_url_kwarg
302
304
  # - edit_upload_form_prefix
303
305
  # - context_object_id_name
@@ -320,7 +322,11 @@ class CreateFromUploadView(View):
320
322
  self.model = self.get_model()
321
323
  self.form_class = self.get_edit_form_class()
322
324
 
323
- self.upload = get_object_or_404(self.upload_model, id=upload_id)
325
+ self.upload = get_object_or_404(
326
+ UploadedFile,
327
+ id=upload_id,
328
+ for_content_type=ContentType.objects.get_for_model(self.model),
329
+ )
324
330
 
325
331
  if self.upload.uploaded_by_user != request.user:
326
332
  raise PermissionDenied
@@ -369,14 +375,17 @@ class CreateFromUploadView(View):
369
375
 
370
376
  class DeleteUploadView(View):
371
377
  # subclasses need to provide:
372
- # - upload_model
373
378
  # - upload_pk_url_kwarg
374
379
 
375
380
  http_method_names = ["post"]
376
381
 
377
382
  def post(self, request, *args, **kwargs):
378
383
  upload_id = kwargs[self.upload_pk_url_kwarg]
379
- upload = get_object_or_404(self.upload_model, id=upload_id)
384
+ upload = get_object_or_404(
385
+ UploadedFile,
386
+ id=upload_id,
387
+ for_content_type=ContentType.objects.get_for_model(self.get_model()),
388
+ )
380
389
 
381
390
  if upload.uploaded_by_user != request.user:
382
391
  raise PermissionDenied
@@ -38,8 +38,9 @@ class UsageView(PermissionCheckedMixin, BaseObjectMixin, BaseListingView):
38
38
  return object.get_latest_revision_as_object()
39
39
  return object
40
40
 
41
- def get_edit_url(self):
42
- return reverse(self.edit_url_name, args=(quote(self.object.pk),))
41
+ def get_edit_url(self, instance):
42
+ if self.edit_url_name:
43
+ return reverse(self.edit_url_name, args=(quote(instance.pk),))
43
44
 
44
45
  def get_usage_url(self, instance):
45
46
  if self.usage_url_name:
@@ -60,10 +61,11 @@ class UsageView(PermissionCheckedMixin, BaseObjectMixin, BaseListingView):
60
61
  "label": capfirst(self.object._meta.verbose_name_plural),
61
62
  }
62
63
  )
63
- if self.edit_url_name:
64
+ edit_url = self.get_edit_url(self.object)
65
+ if edit_url:
64
66
  items.append(
65
67
  {
66
- "url": self.get_edit_url(),
68
+ "url": edit_url,
67
69
  "label": get_latest_str(self.object),
68
70
  }
69
71
  )
@@ -78,13 +80,17 @@ class UsageView(PermissionCheckedMixin, BaseObjectMixin, BaseListingView):
78
80
 
79
81
  @cached_property
80
82
  def header_buttons(self):
81
- return [
82
- HeaderButton(
83
- label=_("Edit"),
84
- url=self.get_edit_url(),
85
- icon_name="edit",
86
- ),
87
- ]
83
+ edit_url = self.get_edit_url(self.object)
84
+ buttons = []
85
+ if edit_url:
86
+ buttons.append(
87
+ HeaderButton(
88
+ label=_("Edit"),
89
+ url=edit_url,
90
+ icon_name="edit",
91
+ )
92
+ )
93
+ return buttons
88
94
 
89
95
  def get_queryset(self):
90
96
  return ReferenceIndex.get_references_to(self.object).group_by_source_object()
@@ -161,17 +161,20 @@ class WorkflowObjectsToModeratePanel(Component):
161
161
  TaskState.objects.reviewable_by(request.user)
162
162
  .select_related(
163
163
  "revision",
164
- "task",
165
164
  "revision__user",
166
165
  "workflow_state",
166
+ "workflow_state__workflow",
167
167
  )
168
168
  .prefetch_related(
169
169
  "revision__content_object",
170
170
  "revision__content_object__latest_revision",
171
- "revision__content_object__live_revision",
172
171
  )
173
172
  .order_by("-started_at")
173
+ .annotate(
174
+ previous_revision_id=Revision.objects.previous_revision_id_subquery(),
175
+ )
174
176
  )
177
+
175
178
  for state in states:
176
179
  obj = state.revision.content_object
177
180
  # Skip task states where the revision's GenericForeignKey points to
@@ -197,17 +200,12 @@ class WorkflowObjectsToModeratePanel(Component):
197
200
  if not getattr(obj, "is_previewable", False):
198
201
  workflow_preview_url_name = None
199
202
 
200
- try:
201
- previous_revision = state.revision.get_previous()
202
- except Revision.DoesNotExist:
203
- previous_revision = None
204
-
205
203
  context["states"].append(
206
204
  {
207
205
  "obj": obj,
208
206
  "revision": state.revision,
209
- "previous_revision": previous_revision,
210
- "live_revision": obj.live_revision,
207
+ "previous_revision_id": state.previous_revision_id,
208
+ "live_revision_id": obj.live_revision_id,
211
209
  "task_state": state,
212
210
  "actions": actions,
213
211
  "workflow_tasks": workflow_tasks,
@@ -233,7 +231,9 @@ class LockedPagesPanel(Component):
233
231
  "locked_pages": Page.objects.filter(
234
232
  locked=True,
235
233
  locked_by=request.user,
236
- ),
234
+ )
235
+ .order_by("-locked_at", "-latest_revision_created_at", "-pk")
236
+ .specific(defer=True),
237
237
  "can_remove_locks": page_permission_policy.user_has_permission(
238
238
  request.user, "unlock"
239
239
  ),
@@ -264,8 +264,11 @@ class RecentEditsPanel(Component):
264
264
  .order_by("-latest_date")[:edit_count]
265
265
  )
266
266
  # Retrieve the page objects for those IDs
267
- pages_mapping = Page.objects.specific().in_bulk(
268
- [log["page_id"] for log in last_edits_dates]
267
+ pages_mapping = (
268
+ Page.objects.specific()
269
+ .prefetch_workflow_states()
270
+ .annotate_approved_schedule()
271
+ .in_bulk([log["page_id"] for log in last_edits_dates])
269
272
  )
270
273
  # Compile a list of (latest edit timestamp, page object) tuples
271
274
  last_edits = []
@@ -11,10 +11,13 @@ from django.utils import timezone
11
11
  from django.utils.dateformat import Formatter
12
12
  from django.utils.encoding import force_str
13
13
  from django.utils.formats import get_format
14
+ from django.utils.functional import cached_property
14
15
  from django.utils.text import capfirst
16
+ from django.utils.translation import gettext as _
15
17
  from openpyxl import Workbook
16
18
  from openpyxl.cell import WriteOnlyCell
17
19
 
20
+ from wagtail.admin.widgets.button import Button
18
21
  from wagtail.coreutils import multigetattr
19
22
 
20
23
 
@@ -301,3 +304,30 @@ class SpreadsheetExportMixin:
301
304
  @property
302
305
  def csv_export_url(self):
303
306
  return self.get_export_url("csv")
307
+
308
+ @cached_property
309
+ def show_export_buttons(self):
310
+ return bool(self.list_export)
311
+
312
+ @cached_property
313
+ def header_more_buttons(self):
314
+ buttons = super().header_more_buttons.copy()
315
+ if self.show_export_buttons:
316
+ buttons.append(
317
+ Button(
318
+ _("Download XLSX"),
319
+ url=self.xlsx_export_url,
320
+ icon_name="download",
321
+ priority=90,
322
+ )
323
+ )
324
+ buttons.append(
325
+ Button(
326
+ _("Download CSV"),
327
+ url=self.csv_export_url,
328
+ icon_name="download",
329
+ priority=100,
330
+ )
331
+ )
332
+
333
+ return buttons
@@ -0,0 +1,73 @@
1
+ from django.contrib.admin.utils import quote
2
+ from django.shortcuts import redirect
3
+ from django.urls import reverse
4
+ from django.utils.functional import cached_property
5
+ from django.utils.text import capfirst
6
+ from django.utils.translation import gettext as _
7
+ from django.utils.translation import gettext_lazy
8
+ from django.views.generic import FormView
9
+
10
+ from wagtail.admin.forms.pages import ParentChooserForm
11
+ from wagtail.admin.views.generic.base import WagtailAdminTemplateMixin
12
+ from wagtail.models import Page
13
+
14
+
15
+ class ChooseParentView(WagtailAdminTemplateMixin, FormView):
16
+ template_name = "wagtailadmin/pages/choose_parent.html"
17
+ model = Page
18
+ index_url_name = None
19
+ page_title = gettext_lazy("Choose parent")
20
+
21
+ def get_form(self):
22
+ if self.request.method == "POST":
23
+ return ParentChooserForm(self.model, self.request.user, self.request.POST)
24
+ return ParentChooserForm(self.model, self.request.user)
25
+
26
+ def get_index_url(self):
27
+ if self.index_url_name:
28
+ return reverse(self.index_url_name)
29
+
30
+ def get_breadcrumbs_items(self):
31
+ items = []
32
+ index_url = self.get_index_url()
33
+ if index_url:
34
+ items.append(
35
+ {
36
+ "url": index_url,
37
+ "label": capfirst(self.model._meta.verbose_name_plural),
38
+ }
39
+ )
40
+ items.append(
41
+ {
42
+ "url": "",
43
+ "label": self.get_page_title(),
44
+ "sublabel": self.get_page_subtitle(),
45
+ }
46
+ )
47
+
48
+ return self.breadcrumbs_items + items
49
+
50
+ def get_page_subtitle(self):
51
+ return self.model.get_verbose_name()
52
+
53
+ @cached_property
54
+ def submit_button_label(self):
55
+ return _("Create a new %(model_name)s") % {
56
+ "model_name": self.model._meta.verbose_name,
57
+ }
58
+
59
+ def form_valid(self, form):
60
+ model_opts = self.model._meta
61
+ parent_id = quote(form.cleaned_data["parent_page"].pk)
62
+ return redirect(
63
+ "wagtailadmin_pages:add",
64
+ model_opts.app_label,
65
+ model_opts.model_name,
66
+ parent_id,
67
+ )
68
+
69
+ def get_context_data(self, **kwargs):
70
+ context = super().get_context_data(**kwargs)
71
+ context["media"] = context["form"].media
72
+ context["submit_button_label"] = self.submit_button_label
73
+ return context
@@ -1,57 +1,34 @@
1
1
  import django_filters
2
- from django import forms
3
2
  from django.core.exceptions import PermissionDenied
3
+ from django.db.models import Q
4
4
  from django.shortcuts import get_object_or_404
5
- from django.utils.decorators import method_decorator
6
- from django.utils.translation import gettext as _
5
+ from django.utils.translation import gettext_lazy
7
6
 
8
- from wagtail.admin.auth import user_has_any_page_permission, user_passes_test
9
- from wagtail.admin.filters import DateRangePickerWidget, WagtailFilterSet
10
7
  from wagtail.admin.views.generic import history
11
- from wagtail.admin.views.reports import ReportView
12
- from wagtail.log_actions import registry as log_action_registry
8
+ from wagtail.admin.views.pages.utils import (
9
+ GenericPageBreadcrumbsMixin,
10
+ )
11
+ from wagtail.admin.widgets import BooleanRadioSelect
13
12
  from wagtail.models import Page, PageLogEntry
13
+ from wagtail.permissions import page_permission_policy
14
14
 
15
15
 
16
- def get_actions_for_filter():
17
- # Only return those actions used by page log entries.
18
- actions = set(PageLogEntry.objects.all().get_actions())
19
- return [
20
- action for action in log_action_registry.get_choices() if action[0] in actions
21
- ]
22
-
23
-
24
- class PageHistoryReportFilterSet(WagtailFilterSet):
25
- action = django_filters.ChoiceFilter(
26
- label=_("Action"),
27
- # choices are set dynamically in __init__()
28
- )
29
- hide_commenting_actions = django_filters.BooleanFilter(
30
- label=_("Hide commenting actions"),
31
- method="filter_hide_commenting_actions",
32
- widget=forms.CheckboxInput,
33
- )
34
- user = django_filters.ModelChoiceFilter(
35
- label=_("User"),
36
- field_name="user",
37
- queryset=lambda request: PageLogEntry.objects.all().get_users(),
38
- )
39
- timestamp = django_filters.DateFromToRangeFilter(
40
- label=_("Date"), widget=DateRangePickerWidget
16
+ class PageHistoryFilterSet(history.HistoryFilterSet):
17
+ is_commenting_action = django_filters.BooleanFilter(
18
+ label=gettext_lazy("Is commenting action"),
19
+ method="filter_is_commenting_action",
20
+ widget=BooleanRadioSelect,
41
21
  )
42
22
 
43
- def filter_hide_commenting_actions(self, queryset, name, value):
44
- if value:
45
- queryset = queryset.exclude(action__startswith="wagtail.comments")
46
- return queryset
23
+ def filter_is_commenting_action(self, queryset, name, value):
24
+ if value is None:
25
+ return queryset
47
26
 
48
- class Meta:
49
- model = PageLogEntry
50
- fields = ["action", "user", "timestamp", "hide_commenting_actions"]
27
+ q = Q(action__startswith="wagtail.comments")
28
+ if value is False:
29
+ q = ~q
51
30
 
52
- def __init__(self, *args, **kwargs):
53
- super().__init__(*args, **kwargs)
54
- self.filters["action"].extra["choices"] = get_actions_for_filter()
31
+ return queryset.filter(q)
55
32
 
56
33
 
57
34
  class PageWorkflowHistoryViewMixin:
@@ -80,28 +57,39 @@ class WorkflowHistoryDetailView(
80
57
  workflow_history_url_name = "wagtailadmin_pages:workflow_history"
81
58
 
82
59
 
83
- class PageHistoryView(ReportView):
60
+ class PageHistoryView(GenericPageBreadcrumbsMixin, history.HistoryView):
84
61
  template_name = "wagtailadmin/pages/history.html"
85
- title = _("Page history")
86
- header_icon = "history"
87
- paginate_by = 20
88
- filterset_class = PageHistoryReportFilterSet
89
-
90
- @method_decorator(user_passes_test(user_has_any_page_permission))
91
- def dispatch(self, request, *args, **kwargs):
92
- self.page = get_object_or_404(Page, id=kwargs.pop("page_id")).specific
93
-
94
- return super().dispatch(request, *args, **kwargs)
95
-
96
- def get_context_data(self, *args, object_list=None, **kwargs):
97
- context = super().get_context_data(*args, object_list=object_list, **kwargs)
98
- context["page"] = self.page
99
- context["subtitle"] = self.page.get_admin_display_title()
100
- context["page_latest_revision"] = self.page.get_latest_revision()
101
-
102
- return context
103
-
104
- def get_queryset(self):
105
- return PageLogEntry.objects.filter(page=self.page).select_related(
106
- "revision", "user", "user__wagtail_userprofile"
107
- )
62
+ filterset_class = PageHistoryFilterSet
63
+ model = Page
64
+ pk_url_kwarg = "page_id"
65
+ permission_policy = page_permission_policy
66
+ any_permission_required = {
67
+ "add",
68
+ "change",
69
+ "publish",
70
+ "bulk_delete",
71
+ "lock",
72
+ "unlock",
73
+ }
74
+ history_url_name = "wagtailadmin_pages:history"
75
+ history_results_url_name = "wagtailadmin_pages:history_results"
76
+ edit_url_name = "wagtailadmin_pages:edit"
77
+ revisions_view_url_name = "wagtailadmin_pages:revisions_view"
78
+ revisions_revert_url_name = "wagtailadmin_pages:revisions_revert"
79
+ revisions_compare_url_name = "wagtailadmin_pages:revisions_compare"
80
+ revisions_unschedule_url_name = "wagtailadmin_pages:revisions_unschedule"
81
+
82
+ def get_object(self):
83
+ return get_object_or_404(Page, id=self.pk).specific
84
+
85
+ def get_page_subtitle(self):
86
+ return self.object.get_admin_display_title()
87
+
88
+ def user_can_unschedule(self):
89
+ return self.object.permissions_for_user(self.request.user).can_unschedule()
90
+
91
+ def get_base_queryset(self):
92
+ return self._annotate_queryset(PageLogEntry.objects.filter(page=self.object))
93
+
94
+ def _annotate_queryset(self, queryset):
95
+ return super()._annotate_queryset(queryset).select_related("page")